diff options
-rw-r--r-- | drivers/net/wireless/ath/ath12k/core.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/debugfs.c | 118 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/debugfs.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/dp.h | 11 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/dp_tx.c | 51 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/dp_tx.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/hal_desc.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/mac.c | 10 |
8 files changed, 200 insertions, 5 deletions
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index e8d2a0c859f6..ef5cf275b834 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -310,6 +310,8 @@ struct ath12k_link_vif { u8 link_id; struct ath12k_vif *ahvif; struct ath12k_rekey_data rekey_data; + struct ath12k_link_stats link_stats; + spinlock_t link_stats_lock; /* Protects updates to link_stats */ u8 current_cntdown_counter; }; diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index e8a2d0eefa43..bab7be9c5a38 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -833,6 +833,124 @@ static const struct file_operations fops_extd_rx_stats = { .open = simple_open, }; +static int ath12k_open_link_stats(struct inode *inode, struct file *file) +{ + struct ath12k_vif *ahvif = inode->i_private; + size_t len = 0, buf_len = (PAGE_SIZE * 2); + struct ath12k_link_stats linkstat; + struct ath12k_link_vif *arvif; + unsigned long links_map; + struct wiphy *wiphy; + int link_id, i; + char *buf; + + if (!ahvif) + return -EINVAL; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + wiphy = ahvif->ah->hw->wiphy; + wiphy_lock(wiphy); + + links_map = ahvif->links_map; + for_each_set_bit(link_id, &links_map, + IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = rcu_dereference_protected(ahvif->link[link_id], + lockdep_is_held(&wiphy->mtx)); + + spin_lock_bh(&arvif->link_stats_lock); + linkstat = arvif->link_stats; + spin_unlock_bh(&arvif->link_stats_lock); + + len += scnprintf(buf + len, buf_len - len, + "link[%d] Tx Unicast Frames Enqueued = %d\n", + link_id, linkstat.tx_enqueued); + len += scnprintf(buf + len, buf_len - len, + "link[%d] Tx Broadcast Frames Enqueued = %d\n", + link_id, linkstat.tx_bcast_mcast); + len += scnprintf(buf + len, buf_len - len, + "link[%d] Tx Frames Completed = %d\n", + link_id, linkstat.tx_completed); + len += scnprintf(buf + len, buf_len - len, + "link[%d] Tx Frames Dropped = %d\n", + link_id, linkstat.tx_dropped); + + len += scnprintf(buf + len, buf_len - len, + "link[%d] Tx Frame descriptor Encap Type = ", + link_id); + + len += scnprintf(buf + len, buf_len - len, + " raw:%d", + linkstat.tx_encap_type[0]); + + len += scnprintf(buf + len, buf_len - len, + " native_wifi:%d", + linkstat.tx_encap_type[1]); + + len += scnprintf(buf + len, buf_len - len, + " ethernet:%d", + linkstat.tx_encap_type[2]); + + len += scnprintf(buf + len, buf_len - len, + "\nlink[%d] Tx Frame descriptor Encrypt Type = ", + link_id); + + for (i = 0; i < HAL_ENCRYPT_TYPE_MAX; i++) { + len += scnprintf(buf + len, buf_len - len, + " %d:%d", i, + linkstat.tx_encrypt_type[i]); + } + len += scnprintf(buf + len, buf_len - len, + "\nlink[%d] Tx Frame descriptor Type = buffer:%d extension:%d\n", + link_id, linkstat.tx_desc_type[0], + linkstat.tx_desc_type[1]); + + len += scnprintf(buf + len, buf_len - len, + "------------------------------------------------------\n"); + } + + wiphy_unlock(wiphy); + + file->private_data = buf; + + return 0; +} + +static int ath12k_release_link_stats(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static ssize_t ath12k_read_link_stats(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + const char *buf = file->private_data; + size_t len = strlen(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations ath12k_fops_link_stats = { + .open = ath12k_open_link_stats, + .release = ath12k_release_link_stats, + .read = ath12k_read_link_stats, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + + debugfs_create_file("link_stats", 0400, vif->debugfs_dir, ahvif, + &ath12k_fops_link_stats); +} + void ath12k_debugfs_soc_create(struct ath12k_base *ab) { bool dput_needed; diff --git a/drivers/net/wireless/ath/ath12k/debugfs.h b/drivers/net/wireless/ath/ath12k/debugfs.h index 4cbcfbb7fa07..74a255a27886 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.h +++ b/drivers/net/wireless/ath/ath12k/debugfs.h @@ -14,6 +14,8 @@ void ath12k_debugfs_register(struct ath12k *ar); void ath12k_debugfs_unregister(struct ath12k *ar); void ath12k_debugfs_fw_stats_process(struct ath12k *ar, struct ath12k_fw_stats *stats); +void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); static inline bool ath12k_debugfs_is_extd_rx_stats_enabled(struct ath12k *ar) { @@ -137,6 +139,11 @@ static inline int ath12k_debugfs_rx_filter(struct ath12k *ar) { return 0; } + +static inline void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ +} #endif /* CONFIG_ATH12K_DEBUGFS */ #endif /* _ATH12K_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index e8dbba0c3bb7..6ce5f853dcdb 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -7,6 +7,7 @@ #ifndef ATH12K_DP_H #define ATH12K_DP_H +#include "hal_desc.h" #include "hal_rx.h" #include "hw.h" @@ -318,6 +319,16 @@ struct ath12k_reo_q_addr_lut { u32 size; }; +struct ath12k_link_stats { + u32 tx_enqueued; + u32 tx_completed; + u32 tx_bcast_mcast; + u32 tx_dropped; + u32 tx_encap_type[HAL_TCL_ENCAP_TYPE_MAX]; + u32 tx_encrypt_type[HAL_ENCRYPT_TYPE_MAX]; + u32 tx_desc_type[HAL_TCL_DESC_TYPE_MAX]; +}; + struct ath12k_dp { struct ath12k_base *ab; u8 num_bank_profiles; diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index b93669348f35..91da0805706f 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -220,7 +220,8 @@ out: } int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif, - struct sk_buff *skb, bool gsn_valid, int mcbc_gsn) + struct sk_buff *skb, bool gsn_valid, int mcbc_gsn, + bool is_mcast) { struct ath12k_base *ab = ar->ab; struct ath12k_dp *dp = &ab->dp; @@ -466,6 +467,17 @@ map: goto fail_unmap_dma; } + spin_lock_bh(&arvif->link_stats_lock); + arvif->link_stats.tx_encap_type[ti.encap_type]++; + arvif->link_stats.tx_encrypt_type[ti.encrypt_type]++; + arvif->link_stats.tx_desc_type[ti.type]++; + + if (is_mcast) + arvif->link_stats.tx_bcast_mcast++; + else + arvif->link_stats.tx_enqueued++; + spin_unlock_bh(&arvif->link_stats_lock); + ath12k_hal_tx_cmd_desc_setup(ab, hal_tcl_desc, &ti); ath12k_hal_srng_access_end(ab, tcl_ring); @@ -489,6 +501,11 @@ fail_unmap_dma: fail_remove_tx_buf: ath12k_dp_tx_release_txbuf(dp, tx_desc, pool_id); + + spin_lock_bh(&arvif->link_stats_lock); + arvif->link_stats.tx_dropped++; + spin_unlock_bh(&arvif->link_stats_lock); + if (tcl_ring_retry) goto tcl_ring_sel; @@ -524,7 +541,10 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, struct ath12k_dp_htt_wbm_tx_status *ts) { struct ieee80211_tx_info *info; + struct ath12k_link_vif *arvif; struct ath12k_skb_cb *skb_cb; + struct ieee80211_vif *vif; + struct ath12k_vif *ahvif; struct ath12k *ar; skb_cb = ATH12K_SKB_CB(msdu); @@ -540,6 +560,19 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc, sizeof(struct hal_tx_msdu_ext_desc), DMA_TO_DEVICE); + vif = skb_cb->vif; + if (vif) { + ahvif = ath12k_vif_to_ahvif(vif); + rcu_read_lock(); + arvif = rcu_dereference(ahvif->link[skb_cb->link_id]); + if (arvif) { + spin_lock_bh(&arvif->link_stats_lock); + arvif->link_stats.tx_completed++; + spin_unlock_bh(&arvif->link_stats_lock); + } + rcu_read_unlock(); + } + memset(&info->status, 0, sizeof(info->status)); if (ts->acked) { @@ -595,7 +628,7 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, */ break; default: - ath12k_warn(ab, "Unknown htt tx status %d\n", wbm_status); + ath12k_warn(ab, "Unknown htt wbm tx status %d\n", wbm_status); break; } } @@ -725,7 +758,10 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, struct ath12k_base *ab = ar->ab; struct ath12k_hw *ah = ar->ah; struct ieee80211_tx_info *info; + struct ath12k_link_vif *arvif; struct ath12k_skb_cb *skb_cb; + struct ieee80211_vif *vif; + struct ath12k_vif *ahvif; if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) { /* Must not happen */ @@ -751,6 +787,17 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, goto exit; } + vif = skb_cb->vif; + if (vif) { + ahvif = ath12k_vif_to_ahvif(vif); + arvif = rcu_dereference(ahvif->link[skb_cb->link_id]); + if (arvif) { + spin_lock_bh(&arvif->link_stats_lock); + arvif->link_stats.tx_completed++; + spin_unlock_bh(&arvif->link_stats_lock); + } + } + info = IEEE80211_SKB_CB(msdu); memset(&info->status, 0, sizeof(info->status)); diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.h b/drivers/net/wireless/ath/ath12k/dp_tx.h index a5904097dc34..10acdcf1fa8f 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.h +++ b/drivers/net/wireless/ath/ath12k/dp_tx.h @@ -17,7 +17,8 @@ struct ath12k_dp_htt_wbm_tx_status { int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab); int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif, - struct sk_buff *skb, bool gsn_valid, int mcbc_gsn); + struct sk_buff *skb, bool gsn_valid, int mcbc_gsn, + bool is_mcast); void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id); int ath12k_dp_tx_htt_h2t_ppdu_stats_req(struct ath12k *ar, u32 mask); diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 63d279fab322..49eededbfa9d 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -1284,11 +1284,13 @@ enum hal_tcl_encap_type { HAL_TCL_ENCAP_TYPE_NATIVE_WIFI, HAL_TCL_ENCAP_TYPE_ETHERNET, HAL_TCL_ENCAP_TYPE_802_3 = 3, + HAL_TCL_ENCAP_TYPE_MAX }; enum hal_tcl_desc_type { HAL_TCL_DESC_TYPE_BUFFER, HAL_TCL_DESC_TYPE_EXT_DESC, + HAL_TCL_DESC_TYPE_MAX, }; enum hal_wbm_htt_tx_comp_status { @@ -1999,6 +2001,7 @@ struct hal_wbm_release_ring_cc_rx { #define HAL_WBM_RELEASE_INFO3_CONTINUATION BIT(2) #define HAL_WBM_RELEASE_INFO5_LOOPING_COUNT GENMASK(31, 28) +#define HAL_ENCRYPT_TYPE_MAX 12 struct hal_wbm_release_ring { struct ath12k_buffer_addr buf_addr_info; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 2b6bdc3d2b11..eb0c461559b9 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3397,6 +3397,9 @@ static void ath12k_mac_init_arvif(struct ath12k_vif *ahvif, arvif->ahvif = ahvif; arvif->link_id = _link_id; + /* Protects the datapath stats update on a per link basis */ + spin_lock_init(&arvif->link_stats_lock); + INIT_LIST_HEAD(&arvif->list); INIT_DELAYED_WORK(&arvif->connection_loss_work, ath12k_mac_vif_sta_connection_loss_work); @@ -7467,7 +7470,7 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, if (!vif->valid_links || !is_mcast || test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) { - ret = ath12k_dp_tx(ar, arvif, skb, false, 0); + ret = ath12k_dp_tx(ar, arvif, skb, false, 0, is_mcast); if (unlikely(ret)) { ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret); ieee80211_free_txskb(ar->ah->hw, skb); @@ -7529,7 +7532,7 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, skip_peer_find: ret = ath12k_dp_tx(tmp_ar, tmp_arvif, - msdu_copied, true, mcbc_gsn); + msdu_copied, true, mcbc_gsn, is_mcast); if (unlikely(ret)) { if (ret == -ENOMEM) { /* Drops are expected during heavy multicast @@ -10805,6 +10808,9 @@ static const struct ieee80211_ops ath12k_ops = { .resume = ath12k_wow_op_resume, .set_wakeup = ath12k_wow_op_set_wakeup, #endif +#ifdef CONFIG_ATH12K_DEBUGFS + .vif_add_debugfs = ath12k_debugfs_op_vif_add, +#endif CFG80211_TESTMODE_CMD(ath12k_tm_cmd) #ifdef CONFIG_ATH12K_DEBUGFS .link_sta_add_debugfs = ath12k_debugfs_link_sta_op_add, |