new file mode 100644
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * This file contains statistics routine.
+ *
+ * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates.
+ */
+
+#include "cfg80211.h"
+#include "stats.h"
+
+void ra6w_stats_rx_update(struct ra6w_stats *stats,
+ const struct ra6w_cfg80211_sta_stats *sta_stats)
+{
+ struct ra6w_stats_rx *rx_stats = stats->rx_stats;
+ const struct ra6w_rx_ext_hdr *last_rx = &sta_stats->last_rx_data_ext;
+
+ if (!stats->stats_enabled || !rx_stats)
+ return;
+
+ rx_stats->format_mode = last_rx->format_mod;
+
+ switch (last_rx->format_mod) {
+ case RA6W_CFG80211_FORMATMOD_NON_HT:
+ rx_stats->flags |= RA6W_STATS_RX_OFDM_BIT;
+ rx_stats->non_ht.ofdm++;
+ fallthrough;
+ case RA6W_CFG80211_FORMATMOD_NON_HT_DUP_OFDM:
+ rx_stats->flags |= RA6W_STATS_RX_CCK_BIT;
+ rx_stats->non_ht.cck++;
+ rx_stats->non_ht.bw = last_rx->ch_bw;
+ break;
+ case RA6W_CFG80211_FORMATMOD_HT_MF:
+ case RA6W_CFG80211_FORMATMOD_HT_GF:
+ rx_stats->flags |= RA6W_STATS_RX_HT_BIT;
+ rx_stats->ht.bw = last_rx->ch_bw & 0x1;
+ rx_stats->ht.nss = last_rx->ht.num_extn_ss & 0x3;
+ rx_stats->ht.mcs = last_rx->ht.mcs & 0x7;
+ rx_stats->ht.gi = last_rx->ht.short_gi & 0x1;
+ rx_stats->ht.ht[rx_stats->ht.gi][rx_stats->ht.mcs]++;
+ break;
+ case RA6W_CFG80211_FORMATMOD_VHT:
+ rx_stats->flags |= RA6W_STATS_RX_VHT_BIT;
+ rx_stats->vht.bw = last_rx->ch_bw;
+ rx_stats->vht.nss = last_rx->vht.nss;
+ rx_stats->vht.mcs = last_rx->vht.mcs;
+ rx_stats->vht.gi = last_rx->vht.short_gi & 0x1;
+ rx_stats->vht.vht[rx_stats->vht.gi][rx_stats->vht.mcs]++;
+ break;
+ case RA6W_CFG80211_FORMATMOD_HE_MU:
+ case RA6W_CFG80211_FORMATMOD_HE_SU:
+ case RA6W_CFG80211_FORMATMOD_HE_ER:
+ case RA6W_CFG80211_FORMATMOD_HE_TB:
+ rx_stats->flags |= RA6W_STATS_RX_HE_SU_BIT;
+ rx_stats->he_su.mcs = last_rx->he.mcs;
+ rx_stats->he_su.nss = last_rx->he.nss;
+ rx_stats->he_su.gi = last_rx->he.gi_type;
+ rx_stats->he_su.he[rx_stats->he_su.gi][rx_stats->he_su.mcs]++;
+ break;
+ default:
+ break;
+ }
+}
+
+int ra6w_stats_init(struct ra6w_stats *stats)
+{
+ struct ra6w_stats_rx *rx_stats = NULL;
+
+ if (stats->stats_enabled)
+ return 0;
+
+ rx_stats = kzalloc(sizeof(*rx_stats), GFP_KERNEL);
+ if (!rx_stats)
+ return -ENOMEM;
+
+ stats->rx_stats = rx_stats;
+ stats->stats_enabled = true;
+
+ return 0;
+}
+
+void ra6w_stats_deinit(struct ra6w_stats *stats)
+{
+ struct ra6w_cfg80211_vif *vif = container_of(stats, struct ra6w_cfg80211_vif, stats);
+ struct ra6w_cfg80211_priv *priv = vif->priv;
+
+ if (!stats->stats_enabled)
+ return;
+
+ ra6w_ctrl_stats_tx_start_req(&priv->core->ctrl, RA6W_STATS_TX_STOP_BIT);
+
+ stats->stats_enabled = false;
+ kfree(stats->rx_stats);
+ stats->rx_stats = NULL;
+}