--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -199,6 +199,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;
@@ -247,6 +257,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/debugfs.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
@@ -1566,6 +1566,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_debugfs_register(struct ath11k *ar)
 {
 	struct ath11k_base *ab = ar->ab;
@@ -1608,6 +1689,9 @@ int ath11k_debugfs_register(struct ath11
 	debugfs_create_file("btcoex_algorithm", 0644,
 			    ar->debug.debugfs_pdev, ar,
 			    &fops_btcoex_algo);
+	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
@@ -4992,9 +4992,9 @@ static int ath11k_mac_mgmt_tx(struct ath
 	 */
 	if (is_prb_rsp &&
 	    atomic_read(&ar->num_pending_mgmt_tx) > ATH11K_PRB_RSP_DROP_THRESHOLD) {
-		ath11k_warn(ar->ab,
+		ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
 			    "dropping probe response as pending queue is almost full\n");
-		return -ENOSPC;
+		return -EBUSY;
 	}
 
 	if (skb_queue_len(q) == ATH11K_TX_MGMT_NUM_PENDING_MAX) {
@@ -5019,8 +5019,10 @@ static void ath11k_mac_op_tx(struct ieee
 	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_key_conf *key = info->control.hw_key;
+	struct ath11k_mgmt_frame_stats *mgmt_stats = &arvif->mgmt_stats;
 	u32 info_flags = info->flags;
 	bool is_prb_rsp;
+	u16 frm_type = 0;
 	int ret;
 
 	memset(skb_cb, 0, sizeof(*skb_cb));
@@ -5034,12 +5036,21 @@ static void ath11k_mac_op_tx(struct ieee
 	if (info_flags & IEEE80211_TX_CTL_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) {
-			ath11k_warn(ar->ab, "failed to queue management frame %d\n",
-				    ret);
+			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
@@ -332,6 +332,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
@@ -5224,6 +5224,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);
@@ -5245,6 +5251,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 */
@@ -6576,6 +6607,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");
@@ -6637,7 +6673,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.
