1*da8fa4e3SBjoern A. Zeeb // SPDX-License-Identifier: ISC 2*da8fa4e3SBjoern A. Zeeb /* 3*da8fa4e3SBjoern A. Zeeb * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. 4*da8fa4e3SBjoern A. Zeeb * Copyright (c) 2018, The Linux Foundation. All rights reserved. 5*da8fa4e3SBjoern A. Zeeb */ 6*da8fa4e3SBjoern A. Zeeb 7*da8fa4e3SBjoern A. Zeeb #include "core.h" 8*da8fa4e3SBjoern A. Zeeb #include "wmi-ops.h" 9*da8fa4e3SBjoern A. Zeeb #include "txrx.h" 10*da8fa4e3SBjoern A. Zeeb #include "debug.h" 11*da8fa4e3SBjoern A. Zeeb 12*da8fa4e3SBjoern A. Zeeb static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar, 13*da8fa4e3SBjoern A. Zeeb struct ath10k_sta_tid_stats *stats, 14*da8fa4e3SBjoern A. Zeeb u32 msdu_count) 15*da8fa4e3SBjoern A. Zeeb { 16*da8fa4e3SBjoern A. Zeeb if (msdu_count == 1) 17*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++; 18*da8fa4e3SBjoern A. Zeeb else if (msdu_count == 2) 19*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++; 20*da8fa4e3SBjoern A. Zeeb else if (msdu_count == 3) 21*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++; 22*da8fa4e3SBjoern A. Zeeb else if (msdu_count == 4) 23*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++; 24*da8fa4e3SBjoern A. Zeeb else if (msdu_count > 4) 25*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++; 26*da8fa4e3SBjoern A. Zeeb } 27*da8fa4e3SBjoern A. Zeeb 28*da8fa4e3SBjoern A. Zeeb static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar, 29*da8fa4e3SBjoern A. Zeeb struct ath10k_sta_tid_stats *stats, 30*da8fa4e3SBjoern A. Zeeb u32 mpdu_count) 31*da8fa4e3SBjoern A. Zeeb { 32*da8fa4e3SBjoern A. Zeeb if (mpdu_count <= 10) 33*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++; 34*da8fa4e3SBjoern A. Zeeb else if (mpdu_count <= 20) 35*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++; 36*da8fa4e3SBjoern A. Zeeb else if (mpdu_count <= 30) 37*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++; 38*da8fa4e3SBjoern A. Zeeb else if (mpdu_count <= 40) 39*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++; 40*da8fa4e3SBjoern A. Zeeb else if (mpdu_count <= 50) 41*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++; 42*da8fa4e3SBjoern A. Zeeb else if (mpdu_count <= 60) 43*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++; 44*da8fa4e3SBjoern A. Zeeb else if (mpdu_count > 60) 45*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++; 46*da8fa4e3SBjoern A. Zeeb } 47*da8fa4e3SBjoern A. Zeeb 48*da8fa4e3SBjoern A. Zeeb void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid, 49*da8fa4e3SBjoern A. Zeeb struct htt_rx_indication_mpdu_range *ranges, 50*da8fa4e3SBjoern A. Zeeb int num_ranges) 51*da8fa4e3SBjoern A. Zeeb { 52*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta; 53*da8fa4e3SBjoern A. Zeeb struct ath10k_peer *peer; 54*da8fa4e3SBjoern A. Zeeb int i; 55*da8fa4e3SBjoern A. Zeeb 56*da8fa4e3SBjoern A. Zeeb if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid))) 57*da8fa4e3SBjoern A. Zeeb return; 58*da8fa4e3SBjoern A. Zeeb 59*da8fa4e3SBjoern A. Zeeb rcu_read_lock(); 60*da8fa4e3SBjoern A. Zeeb spin_lock_bh(&ar->data_lock); 61*da8fa4e3SBjoern A. Zeeb 62*da8fa4e3SBjoern A. Zeeb peer = ath10k_peer_find_by_id(ar, peer_id); 63*da8fa4e3SBjoern A. Zeeb if (!peer || !peer->sta) 64*da8fa4e3SBjoern A. Zeeb goto out; 65*da8fa4e3SBjoern A. Zeeb 66*da8fa4e3SBjoern A. Zeeb arsta = (struct ath10k_sta *)peer->sta->drv_priv; 67*da8fa4e3SBjoern A. Zeeb 68*da8fa4e3SBjoern A. Zeeb for (i = 0; i < num_ranges; i++) 69*da8fa4e3SBjoern A. Zeeb ath10k_rx_stats_update_ampdu_subfrm(ar, 70*da8fa4e3SBjoern A. Zeeb &arsta->tid_stats[tid], 71*da8fa4e3SBjoern A. Zeeb ranges[i].mpdu_count); 72*da8fa4e3SBjoern A. Zeeb 73*da8fa4e3SBjoern A. Zeeb out: 74*da8fa4e3SBjoern A. Zeeb spin_unlock_bh(&ar->data_lock); 75*da8fa4e3SBjoern A. Zeeb rcu_read_unlock(); 76*da8fa4e3SBjoern A. Zeeb } 77*da8fa4e3SBjoern A. Zeeb 78*da8fa4e3SBjoern A. Zeeb void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr, 79*da8fa4e3SBjoern A. Zeeb unsigned long num_msdus, 80*da8fa4e3SBjoern A. Zeeb enum ath10k_pkt_rx_err err, 81*da8fa4e3SBjoern A. Zeeb unsigned long unchain_cnt, 82*da8fa4e3SBjoern A. Zeeb unsigned long drop_cnt, 83*da8fa4e3SBjoern A. Zeeb unsigned long drop_cnt_filter, 84*da8fa4e3SBjoern A. Zeeb unsigned long queued_msdus) 85*da8fa4e3SBjoern A. Zeeb { 86*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta; 87*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta; 88*da8fa4e3SBjoern A. Zeeb struct ieee80211_hdr *hdr; 89*da8fa4e3SBjoern A. Zeeb struct ath10k_sta_tid_stats *stats; 90*da8fa4e3SBjoern A. Zeeb u8 tid = IEEE80211_NUM_TIDS; 91*da8fa4e3SBjoern A. Zeeb bool non_data_frm = false; 92*da8fa4e3SBjoern A. Zeeb 93*da8fa4e3SBjoern A. Zeeb hdr = (struct ieee80211_hdr *)first_hdr; 94*da8fa4e3SBjoern A. Zeeb if (!ieee80211_is_data(hdr->frame_control)) 95*da8fa4e3SBjoern A. Zeeb non_data_frm = true; 96*da8fa4e3SBjoern A. Zeeb 97*da8fa4e3SBjoern A. Zeeb if (ieee80211_is_data_qos(hdr->frame_control)) 98*da8fa4e3SBjoern A. Zeeb tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 99*da8fa4e3SBjoern A. Zeeb 100*da8fa4e3SBjoern A. Zeeb if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm) 101*da8fa4e3SBjoern A. Zeeb return; 102*da8fa4e3SBjoern A. Zeeb 103*da8fa4e3SBjoern A. Zeeb rcu_read_lock(); 104*da8fa4e3SBjoern A. Zeeb 105*da8fa4e3SBjoern A. Zeeb sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL); 106*da8fa4e3SBjoern A. Zeeb if (!sta) 107*da8fa4e3SBjoern A. Zeeb goto exit; 108*da8fa4e3SBjoern A. Zeeb 109*da8fa4e3SBjoern A. Zeeb arsta = (struct ath10k_sta *)sta->drv_priv; 110*da8fa4e3SBjoern A. Zeeb 111*da8fa4e3SBjoern A. Zeeb spin_lock_bh(&ar->data_lock); 112*da8fa4e3SBjoern A. Zeeb stats = &arsta->tid_stats[tid]; 113*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_from_fw += num_msdus; 114*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_unchained += unchain_cnt; 115*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_drop_chained += drop_cnt; 116*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_drop_filter += drop_cnt_filter; 117*da8fa4e3SBjoern A. Zeeb if (err != ATH10K_PKT_RX_ERR_MAX) 118*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_err[err] += queued_msdus; 119*da8fa4e3SBjoern A. Zeeb stats->rx_pkt_queued_for_mac += queued_msdus; 120*da8fa4e3SBjoern A. Zeeb ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid], 121*da8fa4e3SBjoern A. Zeeb num_msdus); 122*da8fa4e3SBjoern A. Zeeb spin_unlock_bh(&ar->data_lock); 123*da8fa4e3SBjoern A. Zeeb 124*da8fa4e3SBjoern A. Zeeb exit: 125*da8fa4e3SBjoern A. Zeeb rcu_read_unlock(); 126*da8fa4e3SBjoern A. Zeeb } 127*da8fa4e3SBjoern A. Zeeb 128*da8fa4e3SBjoern A. Zeeb static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar, 129*da8fa4e3SBjoern A. Zeeb struct ath10k_fw_stats *stats) 130*da8fa4e3SBjoern A. Zeeb { 131*da8fa4e3SBjoern A. Zeeb struct ath10k_fw_extd_stats_peer *peer; 132*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta; 133*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta; 134*da8fa4e3SBjoern A. Zeeb 135*da8fa4e3SBjoern A. Zeeb rcu_read_lock(); 136*da8fa4e3SBjoern A. Zeeb list_for_each_entry(peer, &stats->peers_extd, list) { 137*da8fa4e3SBjoern A. Zeeb sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr, 138*da8fa4e3SBjoern A. Zeeb NULL); 139*da8fa4e3SBjoern A. Zeeb if (!sta) 140*da8fa4e3SBjoern A. Zeeb continue; 141*da8fa4e3SBjoern A. Zeeb arsta = (struct ath10k_sta *)sta->drv_priv; 142*da8fa4e3SBjoern A. Zeeb arsta->rx_duration += (u64)peer->rx_duration; 143*da8fa4e3SBjoern A. Zeeb } 144*da8fa4e3SBjoern A. Zeeb rcu_read_unlock(); 145*da8fa4e3SBjoern A. Zeeb } 146*da8fa4e3SBjoern A. Zeeb 147*da8fa4e3SBjoern A. Zeeb static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar, 148*da8fa4e3SBjoern A. Zeeb struct ath10k_fw_stats *stats) 149*da8fa4e3SBjoern A. Zeeb { 150*da8fa4e3SBjoern A. Zeeb struct ath10k_fw_stats_peer *peer; 151*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta; 152*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta; 153*da8fa4e3SBjoern A. Zeeb 154*da8fa4e3SBjoern A. Zeeb rcu_read_lock(); 155*da8fa4e3SBjoern A. Zeeb list_for_each_entry(peer, &stats->peers, list) { 156*da8fa4e3SBjoern A. Zeeb sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr, 157*da8fa4e3SBjoern A. Zeeb NULL); 158*da8fa4e3SBjoern A. Zeeb if (!sta) 159*da8fa4e3SBjoern A. Zeeb continue; 160*da8fa4e3SBjoern A. Zeeb arsta = (struct ath10k_sta *)sta->drv_priv; 161*da8fa4e3SBjoern A. Zeeb arsta->rx_duration += (u64)peer->rx_duration; 162*da8fa4e3SBjoern A. Zeeb } 163*da8fa4e3SBjoern A. Zeeb rcu_read_unlock(); 164*da8fa4e3SBjoern A. Zeeb } 165*da8fa4e3SBjoern A. Zeeb 166*da8fa4e3SBjoern A. Zeeb void ath10k_sta_update_rx_duration(struct ath10k *ar, 167*da8fa4e3SBjoern A. Zeeb struct ath10k_fw_stats *stats) 168*da8fa4e3SBjoern A. Zeeb { 169*da8fa4e3SBjoern A. Zeeb if (stats->extended) 170*da8fa4e3SBjoern A. Zeeb ath10k_sta_update_extd_stats_rx_duration(ar, stats); 171*da8fa4e3SBjoern A. Zeeb else 172*da8fa4e3SBjoern A. Zeeb ath10k_sta_update_stats_rx_duration(ar, stats); 173*da8fa4e3SBjoern A. Zeeb } 174*da8fa4e3SBjoern A. Zeeb 175*da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, 176*da8fa4e3SBjoern A. Zeeb char __user *user_buf, 177*da8fa4e3SBjoern A. Zeeb size_t count, loff_t *ppos) 178*da8fa4e3SBjoern A. Zeeb { 179*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta = file->private_data; 180*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 181*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = arsta->arvif->ar; 182*da8fa4e3SBjoern A. Zeeb char buf[32]; 183*da8fa4e3SBjoern A. Zeeb int len = 0; 184*da8fa4e3SBjoern A. Zeeb 185*da8fa4e3SBjoern A. Zeeb mutex_lock(&ar->conf_mutex); 186*da8fa4e3SBjoern A. Zeeb len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n", 187*da8fa4e3SBjoern A. Zeeb (arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ? 188*da8fa4e3SBjoern A. Zeeb "auto" : "manual"); 189*da8fa4e3SBjoern A. Zeeb mutex_unlock(&ar->conf_mutex); 190*da8fa4e3SBjoern A. Zeeb 191*da8fa4e3SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, len); 192*da8fa4e3SBjoern A. Zeeb } 193*da8fa4e3SBjoern A. Zeeb 194*da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file, 195*da8fa4e3SBjoern A. Zeeb const char __user *user_buf, 196*da8fa4e3SBjoern A. Zeeb size_t count, loff_t *ppos) 197*da8fa4e3SBjoern A. Zeeb { 198*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta = file->private_data; 199*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 200*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = arsta->arvif->ar; 201*da8fa4e3SBjoern A. Zeeb u32 aggr_mode; 202*da8fa4e3SBjoern A. Zeeb int ret; 203*da8fa4e3SBjoern A. Zeeb 204*da8fa4e3SBjoern A. Zeeb if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode)) 205*da8fa4e3SBjoern A. Zeeb return -EINVAL; 206*da8fa4e3SBjoern A. Zeeb 207*da8fa4e3SBjoern A. Zeeb if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX) 208*da8fa4e3SBjoern A. Zeeb return -EINVAL; 209*da8fa4e3SBjoern A. Zeeb 210*da8fa4e3SBjoern A. Zeeb mutex_lock(&ar->conf_mutex); 211*da8fa4e3SBjoern A. Zeeb if ((ar->state != ATH10K_STATE_ON) || 212*da8fa4e3SBjoern A. Zeeb (aggr_mode == arsta->aggr_mode)) { 213*da8fa4e3SBjoern A. Zeeb ret = count; 214*da8fa4e3SBjoern A. Zeeb goto out; 215*da8fa4e3SBjoern A. Zeeb } 216*da8fa4e3SBjoern A. Zeeb 217*da8fa4e3SBjoern A. Zeeb ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr); 218*da8fa4e3SBjoern A. Zeeb if (ret) { 219*da8fa4e3SBjoern A. Zeeb ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret); 220*da8fa4e3SBjoern A. Zeeb goto out; 221*da8fa4e3SBjoern A. Zeeb } 222*da8fa4e3SBjoern A. Zeeb 223*da8fa4e3SBjoern A. Zeeb arsta->aggr_mode = aggr_mode; 224*da8fa4e3SBjoern A. Zeeb out: 225*da8fa4e3SBjoern A. Zeeb mutex_unlock(&ar->conf_mutex); 226*da8fa4e3SBjoern A. Zeeb return ret; 227*da8fa4e3SBjoern A. Zeeb } 228*da8fa4e3SBjoern A. Zeeb 229*da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_aggr_mode = { 230*da8fa4e3SBjoern A. Zeeb .read = ath10k_dbg_sta_read_aggr_mode, 231*da8fa4e3SBjoern A. Zeeb .write = ath10k_dbg_sta_write_aggr_mode, 232*da8fa4e3SBjoern A. Zeeb .open = simple_open, 233*da8fa4e3SBjoern A. Zeeb .owner = THIS_MODULE, 234*da8fa4e3SBjoern A. Zeeb .llseek = default_llseek, 235*da8fa4e3SBjoern A. Zeeb }; 236*da8fa4e3SBjoern A. Zeeb 237*da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_write_addba(struct file *file, 238*da8fa4e3SBjoern A. Zeeb const char __user *user_buf, 239*da8fa4e3SBjoern A. Zeeb size_t count, loff_t *ppos) 240*da8fa4e3SBjoern A. Zeeb { 241*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta = file->private_data; 242*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 243*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = arsta->arvif->ar; 244*da8fa4e3SBjoern A. Zeeb u32 tid, buf_size; 245*da8fa4e3SBjoern A. Zeeb int ret; 246*da8fa4e3SBjoern A. Zeeb char buf[64] = {0}; 247*da8fa4e3SBjoern A. Zeeb 248*da8fa4e3SBjoern A. Zeeb ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 249*da8fa4e3SBjoern A. Zeeb user_buf, count); 250*da8fa4e3SBjoern A. Zeeb if (ret <= 0) 251*da8fa4e3SBjoern A. Zeeb return ret; 252*da8fa4e3SBjoern A. Zeeb 253*da8fa4e3SBjoern A. Zeeb ret = sscanf(buf, "%u %u", &tid, &buf_size); 254*da8fa4e3SBjoern A. Zeeb if (ret != 2) 255*da8fa4e3SBjoern A. Zeeb return -EINVAL; 256*da8fa4e3SBjoern A. Zeeb 257*da8fa4e3SBjoern A. Zeeb /* Valid TID values are 0 through 15 */ 258*da8fa4e3SBjoern A. Zeeb if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 259*da8fa4e3SBjoern A. Zeeb return -EINVAL; 260*da8fa4e3SBjoern A. Zeeb 261*da8fa4e3SBjoern A. Zeeb mutex_lock(&ar->conf_mutex); 262*da8fa4e3SBjoern A. Zeeb if ((ar->state != ATH10K_STATE_ON) || 263*da8fa4e3SBjoern A. Zeeb (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 264*da8fa4e3SBjoern A. Zeeb ret = count; 265*da8fa4e3SBjoern A. Zeeb goto out; 266*da8fa4e3SBjoern A. Zeeb } 267*da8fa4e3SBjoern A. Zeeb 268*da8fa4e3SBjoern A. Zeeb ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr, 269*da8fa4e3SBjoern A. Zeeb tid, buf_size); 270*da8fa4e3SBjoern A. Zeeb if (ret) { 271*da8fa4e3SBjoern A. Zeeb ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n", 272*da8fa4e3SBjoern A. Zeeb arsta->arvif->vdev_id, sta->addr, tid, buf_size); 273*da8fa4e3SBjoern A. Zeeb } 274*da8fa4e3SBjoern A. Zeeb 275*da8fa4e3SBjoern A. Zeeb ret = count; 276*da8fa4e3SBjoern A. Zeeb out: 277*da8fa4e3SBjoern A. Zeeb mutex_unlock(&ar->conf_mutex); 278*da8fa4e3SBjoern A. Zeeb return ret; 279*da8fa4e3SBjoern A. Zeeb } 280*da8fa4e3SBjoern A. Zeeb 281*da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_addba = { 282*da8fa4e3SBjoern A. Zeeb .write = ath10k_dbg_sta_write_addba, 283*da8fa4e3SBjoern A. Zeeb .open = simple_open, 284*da8fa4e3SBjoern A. Zeeb .owner = THIS_MODULE, 285*da8fa4e3SBjoern A. Zeeb .llseek = default_llseek, 286*da8fa4e3SBjoern A. Zeeb }; 287*da8fa4e3SBjoern A. Zeeb 288*da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file, 289*da8fa4e3SBjoern A. Zeeb const char __user *user_buf, 290*da8fa4e3SBjoern A. Zeeb size_t count, loff_t *ppos) 291*da8fa4e3SBjoern A. Zeeb { 292*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta = file->private_data; 293*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 294*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = arsta->arvif->ar; 295*da8fa4e3SBjoern A. Zeeb u32 tid, status; 296*da8fa4e3SBjoern A. Zeeb int ret; 297*da8fa4e3SBjoern A. Zeeb char buf[64] = {0}; 298*da8fa4e3SBjoern A. Zeeb 299*da8fa4e3SBjoern A. Zeeb ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 300*da8fa4e3SBjoern A. Zeeb user_buf, count); 301*da8fa4e3SBjoern A. Zeeb if (ret <= 0) 302*da8fa4e3SBjoern A. Zeeb return ret; 303*da8fa4e3SBjoern A. Zeeb 304*da8fa4e3SBjoern A. Zeeb ret = sscanf(buf, "%u %u", &tid, &status); 305*da8fa4e3SBjoern A. Zeeb if (ret != 2) 306*da8fa4e3SBjoern A. Zeeb return -EINVAL; 307*da8fa4e3SBjoern A. Zeeb 308*da8fa4e3SBjoern A. Zeeb /* Valid TID values are 0 through 15 */ 309*da8fa4e3SBjoern A. Zeeb if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 310*da8fa4e3SBjoern A. Zeeb return -EINVAL; 311*da8fa4e3SBjoern A. Zeeb 312*da8fa4e3SBjoern A. Zeeb mutex_lock(&ar->conf_mutex); 313*da8fa4e3SBjoern A. Zeeb if ((ar->state != ATH10K_STATE_ON) || 314*da8fa4e3SBjoern A. Zeeb (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 315*da8fa4e3SBjoern A. Zeeb ret = count; 316*da8fa4e3SBjoern A. Zeeb goto out; 317*da8fa4e3SBjoern A. Zeeb } 318*da8fa4e3SBjoern A. Zeeb 319*da8fa4e3SBjoern A. Zeeb ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr, 320*da8fa4e3SBjoern A. Zeeb tid, status); 321*da8fa4e3SBjoern A. Zeeb if (ret) { 322*da8fa4e3SBjoern A. Zeeb ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n", 323*da8fa4e3SBjoern A. Zeeb arsta->arvif->vdev_id, sta->addr, tid, status); 324*da8fa4e3SBjoern A. Zeeb } 325*da8fa4e3SBjoern A. Zeeb ret = count; 326*da8fa4e3SBjoern A. Zeeb out: 327*da8fa4e3SBjoern A. Zeeb mutex_unlock(&ar->conf_mutex); 328*da8fa4e3SBjoern A. Zeeb return ret; 329*da8fa4e3SBjoern A. Zeeb } 330*da8fa4e3SBjoern A. Zeeb 331*da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_addba_resp = { 332*da8fa4e3SBjoern A. Zeeb .write = ath10k_dbg_sta_write_addba_resp, 333*da8fa4e3SBjoern A. Zeeb .open = simple_open, 334*da8fa4e3SBjoern A. Zeeb .owner = THIS_MODULE, 335*da8fa4e3SBjoern A. Zeeb .llseek = default_llseek, 336*da8fa4e3SBjoern A. Zeeb }; 337*da8fa4e3SBjoern A. Zeeb 338*da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_write_delba(struct file *file, 339*da8fa4e3SBjoern A. Zeeb const char __user *user_buf, 340*da8fa4e3SBjoern A. Zeeb size_t count, loff_t *ppos) 341*da8fa4e3SBjoern A. Zeeb { 342*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta = file->private_data; 343*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 344*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = arsta->arvif->ar; 345*da8fa4e3SBjoern A. Zeeb u32 tid, initiator, reason; 346*da8fa4e3SBjoern A. Zeeb int ret; 347*da8fa4e3SBjoern A. Zeeb char buf[64] = {0}; 348*da8fa4e3SBjoern A. Zeeb 349*da8fa4e3SBjoern A. Zeeb ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 350*da8fa4e3SBjoern A. Zeeb user_buf, count); 351*da8fa4e3SBjoern A. Zeeb if (ret <= 0) 352*da8fa4e3SBjoern A. Zeeb return ret; 353*da8fa4e3SBjoern A. Zeeb 354*da8fa4e3SBjoern A. Zeeb ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason); 355*da8fa4e3SBjoern A. Zeeb if (ret != 3) 356*da8fa4e3SBjoern A. Zeeb return -EINVAL; 357*da8fa4e3SBjoern A. Zeeb 358*da8fa4e3SBjoern A. Zeeb /* Valid TID values are 0 through 15 */ 359*da8fa4e3SBjoern A. Zeeb if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 360*da8fa4e3SBjoern A. Zeeb return -EINVAL; 361*da8fa4e3SBjoern A. Zeeb 362*da8fa4e3SBjoern A. Zeeb mutex_lock(&ar->conf_mutex); 363*da8fa4e3SBjoern A. Zeeb if ((ar->state != ATH10K_STATE_ON) || 364*da8fa4e3SBjoern A. Zeeb (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 365*da8fa4e3SBjoern A. Zeeb ret = count; 366*da8fa4e3SBjoern A. Zeeb goto out; 367*da8fa4e3SBjoern A. Zeeb } 368*da8fa4e3SBjoern A. Zeeb 369*da8fa4e3SBjoern A. Zeeb ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr, 370*da8fa4e3SBjoern A. Zeeb tid, initiator, reason); 371*da8fa4e3SBjoern A. Zeeb if (ret) { 372*da8fa4e3SBjoern A. Zeeb ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n", 373*da8fa4e3SBjoern A. Zeeb arsta->arvif->vdev_id, sta->addr, tid, initiator, 374*da8fa4e3SBjoern A. Zeeb reason); 375*da8fa4e3SBjoern A. Zeeb } 376*da8fa4e3SBjoern A. Zeeb ret = count; 377*da8fa4e3SBjoern A. Zeeb out: 378*da8fa4e3SBjoern A. Zeeb mutex_unlock(&ar->conf_mutex); 379*da8fa4e3SBjoern A. Zeeb return ret; 380*da8fa4e3SBjoern A. Zeeb } 381*da8fa4e3SBjoern A. Zeeb 382*da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_delba = { 383*da8fa4e3SBjoern A. Zeeb .write = ath10k_dbg_sta_write_delba, 384*da8fa4e3SBjoern A. Zeeb .open = simple_open, 385*da8fa4e3SBjoern A. Zeeb .owner = THIS_MODULE, 386*da8fa4e3SBjoern A. Zeeb .llseek = default_llseek, 387*da8fa4e3SBjoern A. Zeeb }; 388*da8fa4e3SBjoern A. Zeeb 389*da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_read_peer_debug_trigger(struct file *file, 390*da8fa4e3SBjoern A. Zeeb char __user *user_buf, 391*da8fa4e3SBjoern A. Zeeb size_t count, 392*da8fa4e3SBjoern A. Zeeb loff_t *ppos) 393*da8fa4e3SBjoern A. Zeeb { 394*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta = file->private_data; 395*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 396*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = arsta->arvif->ar; 397*da8fa4e3SBjoern A. Zeeb char buf[8]; 398*da8fa4e3SBjoern A. Zeeb int len = 0; 399*da8fa4e3SBjoern A. Zeeb 400*da8fa4e3SBjoern A. Zeeb mutex_lock(&ar->conf_mutex); 401*da8fa4e3SBjoern A. Zeeb len = scnprintf(buf, sizeof(buf) - len, 402*da8fa4e3SBjoern A. Zeeb "Write 1 to once trigger the debug logs\n"); 403*da8fa4e3SBjoern A. Zeeb mutex_unlock(&ar->conf_mutex); 404*da8fa4e3SBjoern A. Zeeb 405*da8fa4e3SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, len); 406*da8fa4e3SBjoern A. Zeeb } 407*da8fa4e3SBjoern A. Zeeb 408*da8fa4e3SBjoern A. Zeeb static ssize_t 409*da8fa4e3SBjoern A. Zeeb ath10k_dbg_sta_write_peer_debug_trigger(struct file *file, 410*da8fa4e3SBjoern A. Zeeb const char __user *user_buf, 411*da8fa4e3SBjoern A. Zeeb size_t count, loff_t *ppos) 412*da8fa4e3SBjoern A. Zeeb { 413*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta = file->private_data; 414*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 415*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = arsta->arvif->ar; 416*da8fa4e3SBjoern A. Zeeb u8 peer_debug_trigger; 417*da8fa4e3SBjoern A. Zeeb int ret; 418*da8fa4e3SBjoern A. Zeeb 419*da8fa4e3SBjoern A. Zeeb if (kstrtou8_from_user(user_buf, count, 0, &peer_debug_trigger)) 420*da8fa4e3SBjoern A. Zeeb return -EINVAL; 421*da8fa4e3SBjoern A. Zeeb 422*da8fa4e3SBjoern A. Zeeb if (peer_debug_trigger != 1) 423*da8fa4e3SBjoern A. Zeeb return -EINVAL; 424*da8fa4e3SBjoern A. Zeeb 425*da8fa4e3SBjoern A. Zeeb mutex_lock(&ar->conf_mutex); 426*da8fa4e3SBjoern A. Zeeb 427*da8fa4e3SBjoern A. Zeeb if (ar->state != ATH10K_STATE_ON) { 428*da8fa4e3SBjoern A. Zeeb ret = -ENETDOWN; 429*da8fa4e3SBjoern A. Zeeb goto out; 430*da8fa4e3SBjoern A. Zeeb } 431*da8fa4e3SBjoern A. Zeeb 432*da8fa4e3SBjoern A. Zeeb ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr, 433*da8fa4e3SBjoern A. Zeeb ar->wmi.peer_param->debug, peer_debug_trigger); 434*da8fa4e3SBjoern A. Zeeb if (ret) { 435*da8fa4e3SBjoern A. Zeeb ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n", 436*da8fa4e3SBjoern A. Zeeb ret); 437*da8fa4e3SBjoern A. Zeeb goto out; 438*da8fa4e3SBjoern A. Zeeb } 439*da8fa4e3SBjoern A. Zeeb out: 440*da8fa4e3SBjoern A. Zeeb mutex_unlock(&ar->conf_mutex); 441*da8fa4e3SBjoern A. Zeeb return count; 442*da8fa4e3SBjoern A. Zeeb } 443*da8fa4e3SBjoern A. Zeeb 444*da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_peer_debug_trigger = { 445*da8fa4e3SBjoern A. Zeeb .open = simple_open, 446*da8fa4e3SBjoern A. Zeeb .read = ath10k_dbg_sta_read_peer_debug_trigger, 447*da8fa4e3SBjoern A. Zeeb .write = ath10k_dbg_sta_write_peer_debug_trigger, 448*da8fa4e3SBjoern A. Zeeb .owner = THIS_MODULE, 449*da8fa4e3SBjoern A. Zeeb .llseek = default_llseek, 450*da8fa4e3SBjoern A. Zeeb }; 451*da8fa4e3SBjoern A. Zeeb 452*da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file, 453*da8fa4e3SBjoern A. Zeeb char __user *user_buf, 454*da8fa4e3SBjoern A. Zeeb size_t count, loff_t *ppos) 455*da8fa4e3SBjoern A. Zeeb { 456*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta = file->private_data; 457*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 458*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = arsta->arvif->ar; 459*da8fa4e3SBjoern A. Zeeb char buf[20]; 460*da8fa4e3SBjoern A. Zeeb int len = 0; 461*da8fa4e3SBjoern A. Zeeb 462*da8fa4e3SBjoern A. Zeeb spin_lock_bh(&ar->data_lock); 463*da8fa4e3SBjoern A. Zeeb 464*da8fa4e3SBjoern A. Zeeb len = scnprintf(buf, sizeof(buf) - len, "%d\n", 465*da8fa4e3SBjoern A. Zeeb arsta->peer_ps_state); 466*da8fa4e3SBjoern A. Zeeb 467*da8fa4e3SBjoern A. Zeeb spin_unlock_bh(&ar->data_lock); 468*da8fa4e3SBjoern A. Zeeb 469*da8fa4e3SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, len); 470*da8fa4e3SBjoern A. Zeeb } 471*da8fa4e3SBjoern A. Zeeb 472*da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_peer_ps_state = { 473*da8fa4e3SBjoern A. Zeeb .open = simple_open, 474*da8fa4e3SBjoern A. Zeeb .read = ath10k_dbg_sta_read_peer_ps_state, 475*da8fa4e3SBjoern A. Zeeb .owner = THIS_MODULE, 476*da8fa4e3SBjoern A. Zeeb .llseek = default_llseek, 477*da8fa4e3SBjoern A. Zeeb }; 478*da8fa4e3SBjoern A. Zeeb 479*da8fa4e3SBjoern A. Zeeb static char *get_err_str(enum ath10k_pkt_rx_err i) 480*da8fa4e3SBjoern A. Zeeb { 481*da8fa4e3SBjoern A. Zeeb switch (i) { 482*da8fa4e3SBjoern A. Zeeb case ATH10K_PKT_RX_ERR_FCS: 483*da8fa4e3SBjoern A. Zeeb return "fcs_err"; 484*da8fa4e3SBjoern A. Zeeb case ATH10K_PKT_RX_ERR_TKIP: 485*da8fa4e3SBjoern A. Zeeb return "tkip_err"; 486*da8fa4e3SBjoern A. Zeeb case ATH10K_PKT_RX_ERR_CRYPT: 487*da8fa4e3SBjoern A. Zeeb return "crypt_err"; 488*da8fa4e3SBjoern A. Zeeb case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL: 489*da8fa4e3SBjoern A. Zeeb return "peer_idx_inval"; 490*da8fa4e3SBjoern A. Zeeb case ATH10K_PKT_RX_ERR_MAX: 491*da8fa4e3SBjoern A. Zeeb return "unknown"; 492*da8fa4e3SBjoern A. Zeeb } 493*da8fa4e3SBjoern A. Zeeb 494*da8fa4e3SBjoern A. Zeeb return "unknown"; 495*da8fa4e3SBjoern A. Zeeb } 496*da8fa4e3SBjoern A. Zeeb 497*da8fa4e3SBjoern A. Zeeb static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i) 498*da8fa4e3SBjoern A. Zeeb { 499*da8fa4e3SBjoern A. Zeeb switch (i) { 500*da8fa4e3SBjoern A. Zeeb case ATH10K_AMPDU_SUBFRM_NUM_10: 501*da8fa4e3SBjoern A. Zeeb return "upto 10"; 502*da8fa4e3SBjoern A. Zeeb case ATH10K_AMPDU_SUBFRM_NUM_20: 503*da8fa4e3SBjoern A. Zeeb return "11-20"; 504*da8fa4e3SBjoern A. Zeeb case ATH10K_AMPDU_SUBFRM_NUM_30: 505*da8fa4e3SBjoern A. Zeeb return "21-30"; 506*da8fa4e3SBjoern A. Zeeb case ATH10K_AMPDU_SUBFRM_NUM_40: 507*da8fa4e3SBjoern A. Zeeb return "31-40"; 508*da8fa4e3SBjoern A. Zeeb case ATH10K_AMPDU_SUBFRM_NUM_50: 509*da8fa4e3SBjoern A. Zeeb return "41-50"; 510*da8fa4e3SBjoern A. Zeeb case ATH10K_AMPDU_SUBFRM_NUM_60: 511*da8fa4e3SBjoern A. Zeeb return "51-60"; 512*da8fa4e3SBjoern A. Zeeb case ATH10K_AMPDU_SUBFRM_NUM_MORE: 513*da8fa4e3SBjoern A. Zeeb return ">60"; 514*da8fa4e3SBjoern A. Zeeb case ATH10K_AMPDU_SUBFRM_NUM_MAX: 515*da8fa4e3SBjoern A. Zeeb return "0"; 516*da8fa4e3SBjoern A. Zeeb } 517*da8fa4e3SBjoern A. Zeeb 518*da8fa4e3SBjoern A. Zeeb return "0"; 519*da8fa4e3SBjoern A. Zeeb } 520*da8fa4e3SBjoern A. Zeeb 521*da8fa4e3SBjoern A. Zeeb static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i) 522*da8fa4e3SBjoern A. Zeeb { 523*da8fa4e3SBjoern A. Zeeb switch (i) { 524*da8fa4e3SBjoern A. Zeeb case ATH10K_AMSDU_SUBFRM_NUM_1: 525*da8fa4e3SBjoern A. Zeeb return "1"; 526*da8fa4e3SBjoern A. Zeeb case ATH10K_AMSDU_SUBFRM_NUM_2: 527*da8fa4e3SBjoern A. Zeeb return "2"; 528*da8fa4e3SBjoern A. Zeeb case ATH10K_AMSDU_SUBFRM_NUM_3: 529*da8fa4e3SBjoern A. Zeeb return "3"; 530*da8fa4e3SBjoern A. Zeeb case ATH10K_AMSDU_SUBFRM_NUM_4: 531*da8fa4e3SBjoern A. Zeeb return "4"; 532*da8fa4e3SBjoern A. Zeeb case ATH10K_AMSDU_SUBFRM_NUM_MORE: 533*da8fa4e3SBjoern A. Zeeb return ">4"; 534*da8fa4e3SBjoern A. Zeeb case ATH10K_AMSDU_SUBFRM_NUM_MAX: 535*da8fa4e3SBjoern A. Zeeb return "0"; 536*da8fa4e3SBjoern A. Zeeb } 537*da8fa4e3SBjoern A. Zeeb 538*da8fa4e3SBjoern A. Zeeb return "0"; 539*da8fa4e3SBjoern A. Zeeb } 540*da8fa4e3SBjoern A. Zeeb 541*da8fa4e3SBjoern A. Zeeb #define PRINT_TID_STATS(_field, _tabs) \ 542*da8fa4e3SBjoern A. Zeeb do { \ 543*da8fa4e3SBjoern A. Zeeb int k = 0; \ 544*da8fa4e3SBjoern A. Zeeb for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \ 545*da8fa4e3SBjoern A. Zeeb if (ar->sta_tid_stats_mask & BIT(j)) { \ 546*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, \ 547*da8fa4e3SBjoern A. Zeeb "[%02d] %-10lu ", \ 548*da8fa4e3SBjoern A. Zeeb j, stats[j]._field); \ 549*da8fa4e3SBjoern A. Zeeb k++; \ 550*da8fa4e3SBjoern A. Zeeb if (k % 8 == 0) { \ 551*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, \ 552*da8fa4e3SBjoern A. Zeeb buf_len - len, "\n"); \ 553*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, \ 554*da8fa4e3SBjoern A. Zeeb buf_len - len, \ 555*da8fa4e3SBjoern A. Zeeb _tabs); \ 556*da8fa4e3SBjoern A. Zeeb } \ 557*da8fa4e3SBjoern A. Zeeb } \ 558*da8fa4e3SBjoern A. Zeeb } \ 559*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, "\n"); \ 560*da8fa4e3SBjoern A. Zeeb } while (0) 561*da8fa4e3SBjoern A. Zeeb 562*da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file, 563*da8fa4e3SBjoern A. Zeeb char __user *user_buf, 564*da8fa4e3SBjoern A. Zeeb size_t count, loff_t *ppos) 565*da8fa4e3SBjoern A. Zeeb { 566*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta = file->private_data; 567*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 568*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = arsta->arvif->ar; 569*da8fa4e3SBjoern A. Zeeb struct ath10k_sta_tid_stats *stats = arsta->tid_stats; 570*da8fa4e3SBjoern A. Zeeb size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS; 571*da8fa4e3SBjoern A. Zeeb char *buf; 572*da8fa4e3SBjoern A. Zeeb int i, j; 573*da8fa4e3SBjoern A. Zeeb ssize_t ret; 574*da8fa4e3SBjoern A. Zeeb 575*da8fa4e3SBjoern A. Zeeb buf = kzalloc(buf_len, GFP_KERNEL); 576*da8fa4e3SBjoern A. Zeeb if (!buf) 577*da8fa4e3SBjoern A. Zeeb return -ENOMEM; 578*da8fa4e3SBjoern A. Zeeb 579*da8fa4e3SBjoern A. Zeeb mutex_lock(&ar->conf_mutex); 580*da8fa4e3SBjoern A. Zeeb 581*da8fa4e3SBjoern A. Zeeb spin_lock_bh(&ar->data_lock); 582*da8fa4e3SBjoern A. Zeeb 583*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, 584*da8fa4e3SBjoern A. Zeeb "\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n"); 585*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, 586*da8fa4e3SBjoern A. Zeeb "\t\t------------------------------------------\n"); 587*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t"); 588*da8fa4e3SBjoern A. Zeeb PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t"); 589*da8fa4e3SBjoern A. Zeeb 590*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t"); 591*da8fa4e3SBjoern A. Zeeb PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t"); 592*da8fa4e3SBjoern A. Zeeb 593*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, 594*da8fa4e3SBjoern A. Zeeb "MSDUs locally dropped:chained\t"); 595*da8fa4e3SBjoern A. Zeeb PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t"); 596*da8fa4e3SBjoern A. Zeeb 597*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, 598*da8fa4e3SBjoern A. Zeeb "MSDUs locally dropped:filtered\t"); 599*da8fa4e3SBjoern A. Zeeb PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t"); 600*da8fa4e3SBjoern A. Zeeb 601*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, 602*da8fa4e3SBjoern A. Zeeb "MSDUs queued for mac80211\t"); 603*da8fa4e3SBjoern A. Zeeb PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t"); 604*da8fa4e3SBjoern A. Zeeb 605*da8fa4e3SBjoern A. Zeeb for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) { 606*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, 607*da8fa4e3SBjoern A. Zeeb "MSDUs with error:%s\t", get_err_str(i)); 608*da8fa4e3SBjoern A. Zeeb PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t"); 609*da8fa4e3SBjoern A. Zeeb } 610*da8fa4e3SBjoern A. Zeeb 611*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, "\n"); 612*da8fa4e3SBjoern A. Zeeb for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) { 613*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, 614*da8fa4e3SBjoern A. Zeeb "A-MPDU num subframes %s\t", 615*da8fa4e3SBjoern A. Zeeb get_num_ampdu_subfrm_str(i)); 616*da8fa4e3SBjoern A. Zeeb PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t"); 617*da8fa4e3SBjoern A. Zeeb } 618*da8fa4e3SBjoern A. Zeeb 619*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, "\n"); 620*da8fa4e3SBjoern A. Zeeb for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) { 621*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, buf_len - len, 622*da8fa4e3SBjoern A. Zeeb "A-MSDU num subframes %s\t\t", 623*da8fa4e3SBjoern A. Zeeb get_num_amsdu_subfrm_str(i)); 624*da8fa4e3SBjoern A. Zeeb PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t"); 625*da8fa4e3SBjoern A. Zeeb } 626*da8fa4e3SBjoern A. Zeeb 627*da8fa4e3SBjoern A. Zeeb spin_unlock_bh(&ar->data_lock); 628*da8fa4e3SBjoern A. Zeeb 629*da8fa4e3SBjoern A. Zeeb ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 630*da8fa4e3SBjoern A. Zeeb 631*da8fa4e3SBjoern A. Zeeb kfree(buf); 632*da8fa4e3SBjoern A. Zeeb 633*da8fa4e3SBjoern A. Zeeb mutex_unlock(&ar->conf_mutex); 634*da8fa4e3SBjoern A. Zeeb 635*da8fa4e3SBjoern A. Zeeb return ret; 636*da8fa4e3SBjoern A. Zeeb } 637*da8fa4e3SBjoern A. Zeeb 638*da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_tid_stats_dump = { 639*da8fa4e3SBjoern A. Zeeb .open = simple_open, 640*da8fa4e3SBjoern A. Zeeb .read = ath10k_dbg_sta_read_tid_stats, 641*da8fa4e3SBjoern A. Zeeb .owner = THIS_MODULE, 642*da8fa4e3SBjoern A. Zeeb .llseek = default_llseek, 643*da8fa4e3SBjoern A. Zeeb }; 644*da8fa4e3SBjoern A. Zeeb 645*da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file, 646*da8fa4e3SBjoern A. Zeeb char __user *user_buf, 647*da8fa4e3SBjoern A. Zeeb size_t count, loff_t *ppos) 648*da8fa4e3SBjoern A. Zeeb { 649*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta = file->private_data; 650*da8fa4e3SBjoern A. Zeeb struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 651*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = arsta->arvif->ar; 652*da8fa4e3SBjoern A. Zeeb struct ath10k_htt_data_stats *stats; 653*da8fa4e3SBjoern A. Zeeb const char *str_name[ATH10K_STATS_TYPE_MAX] = {"succ", "fail", 654*da8fa4e3SBjoern A. Zeeb "retry", "ampdu"}; 655*da8fa4e3SBjoern A. Zeeb const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"}; 656*da8fa4e3SBjoern A. Zeeb int len = 0, i, j, k, retval = 0; 657*da8fa4e3SBjoern A. Zeeb const int size = 16 * 4096; 658*da8fa4e3SBjoern A. Zeeb char *buf; 659*da8fa4e3SBjoern A. Zeeb 660*da8fa4e3SBjoern A. Zeeb buf = kzalloc(size, GFP_KERNEL); 661*da8fa4e3SBjoern A. Zeeb if (!buf) 662*da8fa4e3SBjoern A. Zeeb return -ENOMEM; 663*da8fa4e3SBjoern A. Zeeb 664*da8fa4e3SBjoern A. Zeeb mutex_lock(&ar->conf_mutex); 665*da8fa4e3SBjoern A. Zeeb 666*da8fa4e3SBjoern A. Zeeb if (!arsta->tx_stats) { 667*da8fa4e3SBjoern A. Zeeb ath10k_warn(ar, "failed to get tx stats"); 668*da8fa4e3SBjoern A. Zeeb mutex_unlock(&ar->conf_mutex); 669*da8fa4e3SBjoern A. Zeeb kfree(buf); 670*da8fa4e3SBjoern A. Zeeb return 0; 671*da8fa4e3SBjoern A. Zeeb } 672*da8fa4e3SBjoern A. Zeeb 673*da8fa4e3SBjoern A. Zeeb spin_lock_bh(&ar->data_lock); 674*da8fa4e3SBjoern A. Zeeb for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) { 675*da8fa4e3SBjoern A. Zeeb for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) { 676*da8fa4e3SBjoern A. Zeeb stats = &arsta->tx_stats->stats[k]; 677*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "%s_%s\n", 678*da8fa4e3SBjoern A. Zeeb str_name[k], 679*da8fa4e3SBjoern A. Zeeb str[j]); 680*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 681*da8fa4e3SBjoern A. Zeeb " VHT MCS %s\n", 682*da8fa4e3SBjoern A. Zeeb str[j]); 683*da8fa4e3SBjoern A. Zeeb for (i = 0; i < ATH10K_VHT_MCS_NUM; i++) 684*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 685*da8fa4e3SBjoern A. Zeeb " %llu ", 686*da8fa4e3SBjoern A. Zeeb stats->vht[j][i]); 687*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\n"); 688*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, " HT MCS %s\n", 689*da8fa4e3SBjoern A. Zeeb str[j]); 690*da8fa4e3SBjoern A. Zeeb for (i = 0; i < ATH10K_HT_MCS_NUM; i++) 691*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 692*da8fa4e3SBjoern A. Zeeb " %llu ", stats->ht[j][i]); 693*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\n"); 694*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 695*da8fa4e3SBjoern A. Zeeb " BW %s (20,5,10,40,80,160 MHz)\n", str[j]); 696*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 697*da8fa4e3SBjoern A. Zeeb " %llu %llu %llu %llu %llu %llu\n", 698*da8fa4e3SBjoern A. Zeeb stats->bw[j][0], stats->bw[j][1], 699*da8fa4e3SBjoern A. Zeeb stats->bw[j][2], stats->bw[j][3], 700*da8fa4e3SBjoern A. Zeeb stats->bw[j][4], stats->bw[j][5]); 701*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 702*da8fa4e3SBjoern A. Zeeb " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]); 703*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 704*da8fa4e3SBjoern A. Zeeb " %llu %llu %llu %llu\n", 705*da8fa4e3SBjoern A. Zeeb stats->nss[j][0], stats->nss[j][1], 706*da8fa4e3SBjoern A. Zeeb stats->nss[j][2], stats->nss[j][3]); 707*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 708*da8fa4e3SBjoern A. Zeeb " GI %s (LGI,SGI)\n", 709*da8fa4e3SBjoern A. Zeeb str[j]); 710*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, " %llu %llu\n", 711*da8fa4e3SBjoern A. Zeeb stats->gi[j][0], stats->gi[j][1]); 712*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 713*da8fa4e3SBjoern A. Zeeb " legacy rate %s (1,2 ... Mbps)\n ", 714*da8fa4e3SBjoern A. Zeeb str[j]); 715*da8fa4e3SBjoern A. Zeeb for (i = 0; i < ATH10K_LEGACY_NUM; i++) 716*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "%llu ", 717*da8fa4e3SBjoern A. Zeeb stats->legacy[j][i]); 718*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\n"); 719*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 720*da8fa4e3SBjoern A. Zeeb " Rate table %s (1,2 ... Mbps)\n ", 721*da8fa4e3SBjoern A. Zeeb str[j]); 722*da8fa4e3SBjoern A. Zeeb for (i = 0; i < ATH10K_RATE_TABLE_NUM; i++) { 723*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "%llu ", 724*da8fa4e3SBjoern A. Zeeb stats->rate_table[j][i]); 725*da8fa4e3SBjoern A. Zeeb if (!((i + 1) % 8)) 726*da8fa4e3SBjoern A. Zeeb len += 727*da8fa4e3SBjoern A. Zeeb scnprintf(buf + len, size - len, "\n "); 728*da8fa4e3SBjoern A. Zeeb } 729*da8fa4e3SBjoern A. Zeeb } 730*da8fa4e3SBjoern A. Zeeb } 731*da8fa4e3SBjoern A. Zeeb 732*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 733*da8fa4e3SBjoern A. Zeeb "\nTX duration\n %llu usecs\n", 734*da8fa4e3SBjoern A. Zeeb arsta->tx_stats->tx_duration); 735*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 736*da8fa4e3SBjoern A. Zeeb "BA fails\n %llu\n", arsta->tx_stats->ba_fails); 737*da8fa4e3SBjoern A. Zeeb len += scnprintf(buf + len, size - len, 738*da8fa4e3SBjoern A. Zeeb "ack fails\n %llu\n", arsta->tx_stats->ack_fails); 739*da8fa4e3SBjoern A. Zeeb spin_unlock_bh(&ar->data_lock); 740*da8fa4e3SBjoern A. Zeeb 741*da8fa4e3SBjoern A. Zeeb if (len > size) 742*da8fa4e3SBjoern A. Zeeb len = size; 743*da8fa4e3SBjoern A. Zeeb retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 744*da8fa4e3SBjoern A. Zeeb kfree(buf); 745*da8fa4e3SBjoern A. Zeeb 746*da8fa4e3SBjoern A. Zeeb mutex_unlock(&ar->conf_mutex); 747*da8fa4e3SBjoern A. Zeeb return retval; 748*da8fa4e3SBjoern A. Zeeb } 749*da8fa4e3SBjoern A. Zeeb 750*da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_tx_stats = { 751*da8fa4e3SBjoern A. Zeeb .read = ath10k_dbg_sta_dump_tx_stats, 752*da8fa4e3SBjoern A. Zeeb .open = simple_open, 753*da8fa4e3SBjoern A. Zeeb .owner = THIS_MODULE, 754*da8fa4e3SBjoern A. Zeeb .llseek = default_llseek, 755*da8fa4e3SBjoern A. Zeeb }; 756*da8fa4e3SBjoern A. Zeeb 757*da8fa4e3SBjoern A. Zeeb void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 758*da8fa4e3SBjoern A. Zeeb struct ieee80211_sta *sta, struct dentry *dir) 759*da8fa4e3SBjoern A. Zeeb { 760*da8fa4e3SBjoern A. Zeeb struct ath10k *ar = hw->priv; 761*da8fa4e3SBjoern A. Zeeb 762*da8fa4e3SBjoern A. Zeeb debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode); 763*da8fa4e3SBjoern A. Zeeb debugfs_create_file("addba", 0200, dir, sta, &fops_addba); 764*da8fa4e3SBjoern A. Zeeb debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp); 765*da8fa4e3SBjoern A. Zeeb debugfs_create_file("delba", 0200, dir, sta, &fops_delba); 766*da8fa4e3SBjoern A. Zeeb debugfs_create_file("peer_debug_trigger", 0600, dir, sta, 767*da8fa4e3SBjoern A. Zeeb &fops_peer_debug_trigger); 768*da8fa4e3SBjoern A. Zeeb debugfs_create_file("dump_tid_stats", 0400, dir, sta, 769*da8fa4e3SBjoern A. Zeeb &fops_tid_stats_dump); 770*da8fa4e3SBjoern A. Zeeb 771*da8fa4e3SBjoern A. Zeeb if (ath10k_peer_stats_enabled(ar) && 772*da8fa4e3SBjoern A. Zeeb ath10k_debug_is_extd_tx_stats_enabled(ar)) 773*da8fa4e3SBjoern A. Zeeb debugfs_create_file("tx_stats", 0400, dir, sta, 774*da8fa4e3SBjoern A. Zeeb &fops_tx_stats); 775*da8fa4e3SBjoern A. Zeeb debugfs_create_file("peer_ps_state", 0400, dir, sta, 776*da8fa4e3SBjoern A. Zeeb &fops_peer_ps_state); 777*da8fa4e3SBjoern A. Zeeb } 778