From 1c29f6fcfc24520277b7401557373fbebee9c17b Mon Sep 17 00:00:00 2001 From: Dinesh Karthikeyan Date: Thu, 23 Jun 2022 17:58:38 +0530 Subject: [PATCH] ath12k: Add missing per peer parameters Add driver_rx_pkts_flow, driver_tx_pkts_flow, reset_tx_stats, reset_rx_stats paramters to display stats for each peer associated. Command to dump the Tx pkts flow in driver: cat /sys/kernel/debug/ieee80211/phyX/netdev\:wlanX/stations/ XX\:XX\:XX\:XX\:XX\:XX/driver_tx_pkts_flow Command to dump the Rx pkts flow in driver: cat /sys/kernel/debug/ieee80211/phyX/netdev\:wlanX/stations/ XX\:XX\:XX\:XX\:XX\:XX/driver_rx_pkts_flow Commands to reset the Tx/Rx pkts flow in driver: echo 1 > /sys/kernel/debug/ieee80211/phyX/netdev\:wlanX/stations/ XX\:XX\:XX\:XX\:XX\:XX/reset_tx_stats echo 1 > /sys/kernel/debug/ieee80211/phyX/netdev\:wlanX/stations/ XX\:XX\:XX\:XX\:XX\:XX/reset_rx_stats Sample output for Tx/Rx packet flow count: cat sys/kernel/debug/ieee80211/phy0/netdev\:wlan0/stations/00\:0 3\:7f\:08\:52\:00/driver_rx_pkts_flow Rx packets inflow from HW: 899 Rx packets outflow from driver: 899 cat sys/kernel/debug/ieee80211/phy0/netdev\:wlan0/stations/00\:0 3\:7f\:08\:52\:00/driver_tx_pkts_flow Tx packets inflow from mac80211: 1797 Tx packets outflow to HW: 1797 Signed-off-by: Dinesh Karthikeyan --- drivers/net/wireless/ath/ath12k/core.h | 12 ++ drivers/net/wireless/ath/ath12k/debugfs.h | 2 + drivers/net/wireless/ath/ath12k/debugfs_sta.c | 185 +++++++++++++++++- drivers/net/wireless/ath/ath12k/dp_rx.c | 45 +++++ drivers/net/wireless/ath/ath12k/mac.c | 11 ++ 5 files changed, 253 insertions(+), 2 deletions(-) --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -498,6 +498,16 @@ struct ath12k_wbm_tx_stats { u64 wbm_tx_comp_stats[HAL_WBM_REL_HTT_TX_COMP_STATUS_MAX]; }; +struct ath12k_driver_tx_pkts_flow { + atomic_t pkts_in; + atomic_t pkts_out; +}; + +struct ath12k_driver_rx_pkts_flow { + atomic_t pkts_frm_hw; + atomic_t pkts_out; +}; + struct ath12k_sta { struct ath12k_vif *arvif; @@ -528,6 +538,8 @@ struct ath12k_sta { bool use_4addr_set; u16 tcl_metadata; u32 bw_prev; + struct ath12k_driver_tx_pkts_flow drv_tx_pkts; + struct ath12k_driver_rx_pkts_flow drv_rx_pkts; }; #define ATH12K_HALF_20MHZ_BW 10 --- a/drivers/net/wireless/ath/ath12k/debugfs.h +++ b/drivers/net/wireless/ath/ath12k/debugfs.h @@ -12,6 +12,8 @@ #define ATH12K_TX_POWER_MAX_VAL 70 #define ATH12K_TX_POWER_MIN_VAL 0 +#define ATH12K_DRV_TX_STATS_SIZE 1024 + /* htt_dbg_ext_stats_type */ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_STATS_RESET = 0, --- a/drivers/net/wireless/ath/ath12k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_sta.c @@ -12,6 +12,7 @@ #include "debug.h" #include "dp_tx.h" #include "debugfs_htt_stats.h" +#include "debugfs.h" void ath12k_debugfs_sta_add_tx_stats(struct ath12k_sta *arsta, struct ath12k_per_peer_tx_stats *peer_stats, @@ -1056,6 +1057,176 @@ static const struct file_operations fops .llseek = default_llseek, }; +static ssize_t +ath12k_dbg_sta_dump_driver_tx_pkts_flow(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath12k_sta *arsta = (struct ath12k_sta *)sta->drv_priv; + struct ath12k *ar = arsta->arvif->ar; + int len = 0, ret_val; + const int size = ATH12K_DRV_TX_STATS_SIZE; + char *buf; + + if (!arsta->tx_stats) + return -ENOENT; + + buf = kzalloc(ATH12K_DRV_TX_STATS_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&ar->conf_mutex); + spin_lock_bh(&ar->ab->base_lock); + len += scnprintf(buf + len, size - len, + "Tx packets inflow from mac80211: %u\n", + atomic_read(&arsta->drv_tx_pkts.pkts_in)); + len += scnprintf(buf + len, size - len, + "Tx packets outflow to HW: %u\n", + atomic_read(&arsta->drv_tx_pkts.pkts_out)); + spin_unlock_bh(&ar->ab->base_lock); + + if (len > size) + len = size; + + ret_val = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + mutex_unlock(&ar->conf_mutex); + return ret_val; +} + +static const struct file_operations fops_driver_tx_pkts_flow = { + .read = ath12k_dbg_sta_dump_driver_tx_pkts_flow, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath12k_dbg_sta_reset_tx_stats(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath12k_sta *arsta = (struct ath12k_sta *)sta->drv_priv; + struct ath12k *ar = arsta->arvif->ar; + int ret, reset; + + if (!arsta->tx_stats || !arsta->wbm_tx_stats) + return -ENOENT; + + ret = kstrtoint_from_user(buf, count, 0, &reset); + if (ret) + return ret; + + if (!reset || reset > 1) + return -EINVAL; + + spin_lock_bh(&ar->ab->base_lock); + memset(arsta->tx_stats, 0, sizeof(*arsta->tx_stats)); + atomic_set(&arsta->drv_tx_pkts.pkts_in, 0); + atomic_set(&arsta->drv_tx_pkts.pkts_out, 0); + memset(arsta->wbm_tx_stats->wbm_tx_comp_stats, 0, sizeof(*arsta->wbm_tx_stats)); + spin_unlock_bh(&ar->ab->base_lock); + + ret = count; + return ret; +} + +static const struct file_operations fops_reset_tx_stats = { + .write = ath12k_dbg_sta_reset_tx_stats, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t +ath12k_dbg_sta_dump_driver_rx_pkts_flow(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath12k_sta *arsta = (struct ath12k_sta *)sta->drv_priv; + struct ath12k *ar = arsta->arvif->ar; + struct ath12k_rx_peer_stats *rx_stats = arsta->rx_stats; + int len = 0, ret_val = 0; + const int size = 1024; + char *buf; + + if (!rx_stats) + return -ENOENT; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&ar->conf_mutex); + spin_lock_bh(&ar->ab->base_lock); + + len += scnprintf(buf + len, size - len, + "Rx packets inflow from HW: %u\n", + atomic_read(&arsta->drv_rx_pkts.pkts_frm_hw)); + len += scnprintf(buf + len, size - len, + "Rx packets outflow from driver: %u\n", + atomic_read(&arsta->drv_rx_pkts.pkts_out)); + + len += scnprintf(buf + len, size - len, "\n"); + + spin_unlock_bh(&ar->ab->base_lock); + + if (len > size) + len = size; + + ret_val = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + mutex_unlock(&ar->conf_mutex); + return ret_val; +} + +static const struct file_operations fops_driver_rx_pkts_flow = { + .read = ath12k_dbg_sta_dump_driver_rx_pkts_flow, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath12k_dbg_sta_reset_rx_stats(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath12k_sta *arsta = (struct ath12k_sta *)sta->drv_priv; + struct ath12k *ar = arsta->arvif->ar; + int ret, reset; + + if (!arsta->rx_stats) + return -ENOENT; + + ret = kstrtoint_from_user(buf, count, 0, &reset); + if (ret) + return ret; + + if (!reset || reset > 1) + return -EINVAL; + + spin_lock_bh(&ar->ab->base_lock); + memset(arsta->rx_stats, 0, sizeof(*arsta->rx_stats)); + atomic_set(&arsta->drv_rx_pkts.pkts_frm_hw, 0); + atomic_set(&arsta->drv_rx_pkts.pkts_out, 0); + spin_unlock_bh(&ar->ab->base_lock); + + ret = count; + return ret; +} + +static const struct file_operations fops_reset_rx_stats = { + .write = ath12k_dbg_sta_reset_rx_stats, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + void ath12k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { @@ -1070,12 +1241,22 @@ void ath12k_debugfs_sta_op_add(struct ie return; } - if (ath12k_debugfs_is_extd_tx_stats_enabled(ar)) + if (ath12k_debugfs_is_extd_tx_stats_enabled(ar)) { debugfs_create_file("tx_stats", 0400, dir, sta, &fops_tx_stats); - if (ath12k_debugfs_is_extd_rx_stats_enabled(ar)) + debugfs_create_file("reset_tx_stats", 0600, dir, sta, + &fops_reset_tx_stats); + debugfs_create_file("driver_tx_pkts_flow", 0400, dir, sta, + &fops_driver_tx_pkts_flow); + } + if (ath12k_debugfs_is_extd_rx_stats_enabled(ar)) { debugfs_create_file("rx_stats", 0400, dir, sta, &fops_rx_stats); + debugfs_create_file("reset_rx_stats", 0600, dir, sta, + &fops_reset_rx_stats); + debugfs_create_file("driver_rx_pkts_flow", 0400, dir, sta, + &fops_driver_rx_pkts_flow); + } debugfs_create_file("htt_peer_stats", 0400, dir, sta, &fops_htt_peer_stats); --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2766,6 +2766,7 @@ static void ath12k_dp_rx_deliver_msdu(st u8 decap = DP_RX_DECAP_TYPE_RAW; bool is_mcbc = rxcb->is_mcbc; bool is_eapol = rxcb->is_eapol; + struct ath12k_sta *arsta = NULL; if (status->encoding == RX_ENC_HE && !(status->flag & RX_FLAG_RADIOTAP_HE) && !(status->flag & RX_FLAG_SKIP_MONITOR)) { @@ -2827,6 +2828,18 @@ static void ath12k_dp_rx_deliver_msdu(st rx_status->flag |= RX_FLAG_8023; ieee80211_rx_napi(ar->ah->hw, pubsta, msdu, napi); + + if (ath12k_debugfs_is_extd_rx_stats_enabled(ar)) { + if (!(status->flag & RX_FLAG_ONLY_MONITOR)) { + spin_lock_bh(&ar->ab->base_lock); + if (peer && peer->sta) + arsta = + (struct ath12k_sta *)peer->sta->drv_priv; + spin_unlock_bh(&ar->ab->base_lock); + if (arsta) + atomic_inc(&arsta->drv_rx_pkts.pkts_out); + } + } } static int ath12k_dp_rx_process_msdu(struct ath12k *ar, @@ -2971,6 +2984,9 @@ int ath12k_dp_rx_process(struct ath12k_b u32 *rx_desc; int i; u64 desc_va; + struct ath12k_sta *arsta = NULL; + struct ath12k_peer *peer = NULL; + struct ath12k *ar; __skb_queue_head_init(&msdu_list); @@ -2992,6 +3008,8 @@ try_again: mac_id = u32_get_bits(desc.info0, HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); + ar = ab->pdevs[mac_id].ar; + desc_va = ((u64)desc.buf_va_hi << 32 | desc.buf_va_lo); desc_info = (struct ath12k_rx_desc_info *)((unsigned long)desc_va); @@ -3037,6 +3055,19 @@ try_again: rxcb->tid = u32_get_bits(desc.rx_mpdu_info.info0, RX_MPDU_DESC_INFO0_TID); + if (ath12k_debugfs_is_extd_rx_stats_enabled(ar) && rxcb->peer_id) { + rcu_read_lock(); + spin_lock_bh(&ab->base_lock); + peer = ath12k_peer_find_by_id(ab, rxcb->peer_id); + if (peer && peer->sta) + arsta = + (struct ath12k_sta *)peer->sta->drv_priv; + spin_unlock_bh(&ab->base_lock); + if (arsta) + atomic_inc(&arsta->drv_rx_pkts.pkts_frm_hw); + rcu_read_unlock(); + } + __skb_queue_tail(&msdu_list, msdu); if (!rxcb->is_continuation) { @@ -3874,6 +3905,8 @@ static int ath12k_dp_rx_h_null_q_desc(st struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; bool fast_rx; + struct ath12k_sta *arsta = NULL; + struct ath12k_peer *peer = NULL; msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc); peer_id = ath12k_dp_rx_h_peer_id(ab, desc); @@ -3935,6 +3968,18 @@ static int ath12k_dp_rx_h_null_q_desc(st * rx with mac80211. Need not worry about cleaning up amsdu_list. */ + if (ath12k_debugfs_is_extd_rx_stats_enabled(ar)) { + peer_id = ath12k_dp_rx_h_peer_id(ar->ab, desc); + spin_lock_bh(&ar->ab->base_lock); + if (peer_id) + peer = ath12k_peer_find_by_id(ar->ab, rxcb->peer_id); + if (peer && peer->sta) + arsta = (struct ath12k_sta *)peer->sta->drv_priv; + spin_unlock_bh(&ar->ab->base_lock); + if (arsta) + atomic_inc(&arsta->drv_rx_pkts.pkts_frm_hw); + } + return 0; } --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6469,6 +6469,7 @@ static void ath12k_mac_setup_he_eht_cap( band->iftype_data = ar->mac.iftype[NL80211_BAND_6GHZ]; band->n_iftype_data = count; } + } static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant) @@ -6726,6 +6727,7 @@ static void ath12k_mac_op_tx(struct ieee struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_key_conf *key = info->control.hw_key; struct ath12k_sta *arsta = NULL; + struct ieee80211_sta *sta = control->sta; u32 info_flags = info->flags; bool is_prb_rsp; int ret; @@ -6763,6 +6765,15 @@ static void ath12k_mac_op_tx(struct ieee ret); ieee80211_free_txskb(ah->hw, skb); } + + if (ath12k_debugfs_is_extd_tx_stats_enabled(ar) && sta) { + arsta = (struct ath12k_sta *)sta->drv_priv; + if (arsta) { + atomic_inc(&arsta->drv_tx_pkts.pkts_in); + if (!ret) + atomic_inc(&arsta->drv_tx_pkts.pkts_out); + } + } } void ath12k_mac_drain_tx(struct ath12k *ar)