wlan-ap-Telecominfraproject/feeds/wifi-ax/mac80211/patches/qca/142-ath11k-adding-support-for-mgmt-frame-stats.patch
John Crispin 528a778e38 open-converged-wireless: Import 21.02 based uCentral tree
Signed-off-by: John Crispin <john@phrozen.org>
2021-03-25 12:19:47 +01:00

277 lines
8.7 KiB
Diff

--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -189,6 +189,16 @@ enum ath11k_dev_flags {
ATH11K_FLAG_FW_RESTART_FOR_HOST,
};
+#define ATH11K_STATS_MGMT_FRM_TYPE_MAX 16
+
+struct ath11k_mgmt_frame_stats {
+ u32 tx_succ_cnt[ATH11K_STATS_MGMT_FRM_TYPE_MAX];
+ u32 tx_fail_cnt[ATH11K_STATS_MGMT_FRM_TYPE_MAX];
+ u32 rx_cnt[ATH11K_STATS_MGMT_FRM_TYPE_MAX];
+ u32 tx_compl_succ[ATH11K_STATS_MGMT_FRM_TYPE_MAX];
+ u32 tx_compl_fail[ATH11K_STATS_MGMT_FRM_TYPE_MAX];
+};
+
struct ath11k_vif {
u32 vdev_id;
enum wmi_vdev_type vdev_type;
@@ -236,6 +246,7 @@ struct ath11k_vif {
bool wpaie_present;
struct ieee80211_chanctx_conf chanctx;
struct dentry *debugfs_twt;
+ struct ath11k_mgmt_frame_stats mgmt_stats;
};
struct ath11k_vif_iter {
--- a/drivers/net/wireless/ath/ath11k/debug.c
+++ b/drivers/net/wireless/ath/ath11k/debug.c
@@ -1611,6 +1611,87 @@ static const struct file_operations fops
.open = simple_open
};
+static ssize_t ath11k_dump_mgmt_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k *ar = file->private_data;
+ struct ath11k_vif *arvif = NULL;
+ struct ath11k_mgmt_frame_stats *mgmt_stats;
+ int len = 0, ret, i;
+ int size = (TARGET_NUM_VDEVS - 1) * 1500;
+ char *buf;
+ const char *mgmt_frm_type[ATH11K_STATS_MGMT_FRM_TYPE_MAX-1] = {"assoc_req", "assoc_resp",
+ "reassoc_req", "reassoc_resp",
+ "probe_req", "probe_resp",
+ "timing_advertisement", "reserved",
+ "beacon", "atim", "disassoc",
+ "auth", "deauth", "action", "action_no_ack"};
+
+ if (ar->state != ATH11K_STATE_ON)
+ return -ENETDOWN;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&ar->conf_mutex);
+ spin_lock_bh(&ar->data_lock);
+
+ list_for_each_entry (arvif, &ar->arvifs, list) {
+ if (!arvif)
+ break;
+
+ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
+ continue;
+
+ mgmt_stats = &arvif->mgmt_stats;
+ len += scnprintf(buf + len, size - len, "MGMT frame stats for vdev %u :\n",
+ arvif->vdev_id);
+ len += scnprintf(buf + len, size - len, " TX stats :\n ");
+ len += scnprintf(buf + len, size - len, " Success frames:\n");
+ for (i = 0; i < ATH11K_STATS_MGMT_FRM_TYPE_MAX-1; i++)
+ len += scnprintf(buf + len, size - len, " %s: %d\n", mgmt_frm_type[i],
+ mgmt_stats->tx_succ_cnt[i]);
+
+ len += scnprintf(buf + len, size - len, " Failed frames:\n");
+
+ for (i = 0; i < ATH11K_STATS_MGMT_FRM_TYPE_MAX-1; i++)
+ len += scnprintf(buf + len, size - len, " %s: %d\n", mgmt_frm_type[i],
+ mgmt_stats->tx_fail_cnt[i]);
+
+ len += scnprintf(buf + len, size - len, " RX stats :\n");
+ len += scnprintf(buf + len, size - len, " Success frames:\n");
+ for (i = 0; i < ATH11K_STATS_MGMT_FRM_TYPE_MAX-1; i++)
+ len += scnprintf(buf + len, size - len, " %s: %d\n", mgmt_frm_type[i],
+ mgmt_stats->rx_cnt[i]);
+
+ len += scnprintf(buf + len, size - len, " Tx completion stats :\n");
+ len += scnprintf(buf + len, size - len, " success completions:\n");
+ for (i = 0; i < ATH11K_STATS_MGMT_FRM_TYPE_MAX-1; i++)
+ len += scnprintf(buf + len, size - len, " %s: %d\n", mgmt_frm_type[i],
+ mgmt_stats->tx_compl_succ[i]);
+ len += scnprintf(buf + len, size - len, " failure completions:\n");
+ for (i = 0; i < ATH11K_STATS_MGMT_FRM_TYPE_MAX-1; i++)
+ len += scnprintf(buf + len, size - len, " %s: %d\n", mgmt_frm_type[i],
+ mgmt_stats->tx_compl_fail[i]);
+ }
+
+ spin_unlock_bh(&ar->data_lock);
+
+ if (len > size)
+ len = size;
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, len);
+ mutex_unlock(&ar->conf_mutex);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations fops_dump_mgmt_stats = {
+ .read = ath11k_dump_mgmt_stats,
+ .open = simple_open
+};
+
int ath11k_debug_register(struct ath11k *ar)
{
struct ath11k_base *ab = ar->ab;
@@ -1655,6 +1736,8 @@ int ath11k_debug_register(struct ath11k
debugfs_create_file("btcoex_duty_cycle", 0644,
ar->debug.debugfs_pdev, ar,
&fops__btcoex_duty_cycle);
+ debugfs_create_file("dump_mgmt_stats", 0644, ar->debug.debugfs_pdev,
+ ar, &fops_dump_mgmt_stats);
if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {
debugfs_create_file("dfs_simulate_radar", 0200,
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -4822,20 +4822,35 @@ static void ath11k_mac_op_tx(struct ieee
struct ieee80211_vif *vif = info->control.vif;
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ath11k_mgmt_frame_stats *mgmt_stats = &arvif->mgmt_stats;
bool is_prb_rsp;
int ret;
+ u16 frm_type = 0;
if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) {
skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP;
} else if (ieee80211_is_mgmt(hdr->frame_control)) {
+ frm_type = FIELD_GET(IEEE80211_FCTL_STYPE, hdr->frame_control);
is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
ret = ath11k_mac_mgmt_tx(ar, skb, is_prb_rsp);
if (ret) {
- if (ret != -EBUSY) {
+ if (ret != -EBUSY)
ath11k_warn(ar->ab, "failed to queue management frame %d\n",
ret);
- }
ieee80211_free_txskb(ar->hw, skb);
+ spin_lock_bh(&ar->data_lock);
+
+ mgmt_stats->tx_fail_cnt[frm_type]++;
+
+ spin_unlock_bh(&ar->data_lock);
+
+ } else {
+
+ spin_lock_bh(&ar->data_lock);
+
+ mgmt_stats->tx_succ_cnt[frm_type]++;
+
+ spin_unlock_bh(&ar->data_lock);
}
return;
}
--- a/drivers/net/wireless/ath/ath11k/peer.c
+++ b/drivers/net/wireless/ath/ath11k/peer.c
@@ -310,6 +310,7 @@ int ath11k_peer_create(struct ath11k *ar
peer->sec_type = HAL_ENCRYPT_TYPE_OPEN;
peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
+ peer->vif = arvif->vif;
ar->num_peers++;
--- a/drivers/net/wireless/ath/ath11k/peer.h
+++ b/drivers/net/wireless/ath/ath11k/peer.h
@@ -20,6 +20,7 @@ struct ppdu_user_delayba {
struct ath11k_peer {
struct list_head list;
struct ieee80211_sta *sta;
+ struct ieee80211_vif *vif;
int vdev_id;
u8 addr[ETH_ALEN];
int peer_id;
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -4846,6 +4846,12 @@ static int wmi_process_mgmt_tx_comp(stru
struct sk_buff *msdu;
struct ieee80211_tx_info *info;
struct ath11k_skb_cb *skb_cb;
+ struct ieee80211_hdr *hdr;
+ struct ath11k_peer *peer;
+ struct ieee80211_vif *vif;
+ struct ath11k_vif *arvif;
+ struct ath11k_mgmt_frame_stats *mgmt_stats;
+ u16 frm_type;
spin_lock_bh(&ar->txmgmt_idr_lock);
msdu = idr_find(&ar->txmgmt_idr, desc_id);
@@ -4867,6 +4873,31 @@ static int wmi_process_mgmt_tx_comp(stru
if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status)
info->flags |= IEEE80211_TX_STAT_ACK;
+ hdr = (struct ieee80211_hdr *)msdu->data;
+ frm_type = FIELD_GET(IEEE80211_FCTL_STYPE, hdr->frame_control);
+
+ spin_lock_bh(&ar->ab->base_lock);
+ peer = ath11k_peer_find_by_addr(ar->ab, hdr->addr2);
+ if (!peer) {
+ spin_unlock_bh(&ar->ab->base_lock);
+ ath11k_warn(ar->ab, "failed to find peer to update txcompl mgmt stats\n");
+ goto skip_mgmt_stats;
+ }
+
+ vif = peer->vif;
+ spin_unlock_bh(&ar->ab->base_lock);
+
+ spin_lock_bh(&ar->data_lock);
+ arvif = ath11k_vif_to_arvif(vif);
+ mgmt_stats = &arvif->mgmt_stats;
+
+ if (!status)
+ mgmt_stats->tx_compl_succ[frm_type]++;
+ else
+ mgmt_stats->tx_compl_fail[frm_type]++;
+ spin_unlock_bh(&ar->data_lock);
+
+skip_mgmt_stats:
ieee80211_tx_status_irqsafe(ar->hw, msdu);
/* WARN when we received this event without doing any mgmt tx */
@@ -6199,6 +6230,11 @@ static void ath11k_mgmt_rx_event(struct
struct ieee80211_hdr *hdr;
u16 fc;
struct ieee80211_supported_band *sband;
+ struct ath11k_peer *peer;
+ struct ieee80211_vif *vif;
+ struct ath11k_vif *arvif;
+ struct ath11k_mgmt_frame_stats *mgmt_stats;
+ u16 frm_type = 0;
if (ath11k_pull_mgmt_rx_params_tlv(ab, skb, &rx_ev) != 0) {
ath11k_warn(ab, "failed to extract mgmt rx event");
@@ -6260,7 +6296,30 @@ static void ath11k_mgmt_rx_event(struct
hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control);
+ frm_type = FIELD_GET(IEEE80211_FCTL_STYPE, fc);
+
+ spin_lock_bh(&ab->base_lock);
+
+ peer = ath11k_peer_find_by_addr(ab, hdr->addr1);
+ if(!peer)
+ peer = ath11k_peer_find_by_addr(ab, hdr->addr3);
+ if (!peer) {
+ spin_unlock_bh(&ab->base_lock);
+ goto skip_mgmt_stats;
+ }
+
+ vif = peer->vif;
+
+ spin_unlock_bh(&ab->base_lock);
+ spin_lock_bh(&ar->data_lock);
+
+ arvif = ath11k_vif_to_arvif(vif);
+ mgmt_stats = &arvif->mgmt_stats;
+ mgmt_stats->rx_cnt[frm_type]++;
+
+ spin_unlock_bh(&ar->data_lock);
+skip_mgmt_stats:
/* Firmware is guaranteed to report all essential management frames via
* WMI while it can deliver some extra via HTT. Since there can be
* duplicates split the reporting wrt monitor/sniffing.