]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: rtw89: debug: bb_info entry including TX rate count for WiFi 7 chips
authorKuan-Chung Chen <damon.chen@realtek.com>
Wed, 29 Apr 2026 13:26:21 +0000 (21:26 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Wed, 6 May 2026 08:04:57 +0000 (16:04 +0800)
Enhance TX performance visibility for WiFi 7 chips by introducing TX
rate count tracking. This is critical for debugging and validation.
Additionally, introduce a new debugfs bb_info to enable and provide
baseband status.

Usage of bb_info debugfs:
  $ echo enable 1 > bb_info  // Start logging BB statistics information
  $ echo mac_id 0 > bb_info  // Specify mac_id for TX rate count tracking

The output of bb_info:

  TP TX: 0 [0] Mbps, RX: 0 [0] Mbps
  Avg packet length: TX=118, RX=136
  TF: 0
  TX count [0]:
     Legacy: [0, 0, 0, 0]
       OFDM: [0, 0, 0, 0, 0, 0, 0, 0]
    MCS 1SS: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    MCS 2SS: [183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

  [PHY 0]
  == RSSI/RX Rate
  Beacon: 19 (-41 dBm)
  RX count:
     Legacy: [0, 0, 0, 0]
       OFDM: [0, 0, 0, 0, 0, 0, 0, 0]
       HT 0: [0, 0, 0, 0, 0, 0, 0, 0]
       HT 1: [0, 0, 0, 0, 0, 0, 0, 0]
    VHT 1SS: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0][0, 0]
    VHT 2SS: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0][0, 0]
     HE 1SS: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
     HE 2SS: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    EHT 1SS: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0][0, 0]
    EHT 2SS: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185]

  TX rate [0, 2]: EHT 2SS MCS-0 GI:0.8 FB_G BW:160 (hw_rate=0x420) ==> agg_wait=-1 (1)
  RX rate [0, 2]: EHT 2SS MCS-13 GI:0.8 BW:160 (hw_rate=0x42d)
  RSSI: -43 dBm (raw=134, prev=135) [-43, -44]
  EVM: [38.75, (41.50, 43.00)]    SNR: 39

Signed-off-by: Kuan-Chung Chen <damon.chen@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20260429132625.1659182-4-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/debug.c
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/fw.h
drivers/net/wireless/realtek/rtw89/mac80211.c
drivers/net/wireless/realtek/rtw89/phy.c
drivers/net/wireless/realtek/rtw89/phy.h

index 81f3ae21dc18b4dfd329652f76ed535bc9aec307..d8f83623e54a689e4efb4712675852ae7f461965 100644 (file)
@@ -6613,6 +6613,8 @@ int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
        if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw))
                rtw89_chip_rfk_channel(rtwdev, target);
 
+       rtw89_fw_h2c_tx_history(rtwdev, target->mac_id);
+
        rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR;
 
 wake_queue:
index f15a0c43ef6da46e7bf9c7e73fffc29c61767de3..c4396f0100bef5ac43109de2ba8474a0b5add400 100644 (file)
@@ -4511,6 +4511,15 @@ struct rtw89_antdiv_info {
        bool get_stats;
 };
 
+struct rtw89_bb_stat_cfg {
+       bool enable;
+       u16 mac_id;
+};
+
+struct rtw89_phy_info {
+       struct rtw89_bb_stat_cfg bb_stat_cfg;
+};
+
 enum rtw89_chanctx_state {
        RTW89_CHANCTX_STATE_MCC_START,
        RTW89_CHANCTX_STATE_MCC_STOP,
@@ -4831,6 +4840,7 @@ enum rtw89_fw_feature {
        RTW89_FW_FEATURE_SIM_SER_L0L1_BY_HALT_H2C,
        RTW89_FW_FEATURE_LPS_ML_INFO_V1,
        RTW89_FW_FEATURE_SER_POST_RECOVER_DMAC,
+       RTW89_FW_FEATURE_TX_HISTORY_V1,
 
        NUM_OF_RTW89_FW_FEATURES,
 };
@@ -5342,9 +5352,11 @@ struct rtw89_beacon_stat {
 
 DECLARE_EWMA(thermal, 4, 4);
 
+#define RTW89_TX_RATE_NR 40
 struct rtw89_phy_stat {
        struct ewma_thermal avg_thermal[RF_PATH_MAX];
        u8 last_thermal_max;
+       u32 tx_rate_cnt[RTW89_TX_RATE_NR];
        struct rtw89_beacon_stat bcn_stat;
 };
 
@@ -6308,6 +6320,7 @@ struct rtw89_dev {
        struct rtw89_phy_efuse_gain efuse_gain;
        struct rtw89_phy_ul_tb_info ul_tb_info;
        struct rtw89_antdiv_info antdiv;
+       struct rtw89_phy_info phy_info;
 
        struct rtw89_bb_ctx {
                enum rtw89_phy_idx phy_idx;
index 2d953bec149b8f99f30d393fbf5c845f23de145b..b82b13645fb09c0596b9bcda91804a1ef8c36170 100644 (file)
@@ -85,6 +85,7 @@ struct rtw89_debugfs {
        struct rtw89_debugfs_priv btc_manual;
        struct rtw89_debugfs_priv fw_log_manual;
        struct rtw89_debugfs_priv phy_info;
+       struct rtw89_debugfs_priv bb_info;
        struct rtw89_debugfs_priv stations;
        struct rtw89_debugfs_priv disable_dm;
        struct rtw89_debugfs_priv static_pd_th;
@@ -4016,15 +4017,15 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
 }
 
 static int
-rtw89_debug_append_rx_rate(char *buf, size_t bufsz, struct rtw89_pkt_stat *pkt_stat,
-                          enum rtw89_hw_rate first_rate, int len)
+rtw89_debug_append_rate(char *buf, size_t bufsz, const u32 *rate_cnt,
+                       int first_rate, int len)
 {
        char *p = buf, *end = buf + bufsz;
        int i;
 
        for (i = 0; i < len; i++)
                p += scnprintf(p, end - p, "%s%u", i == 0 ? "" : ", ",
-                              pkt_stat->rx_rate_cnt[first_rate + i]);
+                              rate_cnt[first_rate + i]);
 
        return p - buf;
 }
@@ -4051,6 +4052,17 @@ static const struct rtw89_rx_rate_cnt_info {
        {FIRST_RATE_GEV1(EHT_NSS2_MCS0), 14, 0, "EHT 2SS:"},
 };
 
+static const struct rtw89_tx_rate_cnt_info {
+       int first_rate;
+       int len;
+       const char *rate_mode;
+} rtw89_tx_rate_cnt_infos[] = {
+       {0, 4, "Legacy:"},
+       {4, 8, "OFDM:"},
+       {12, 14, "MCS 1SS:"},
+       {26, 14, "MCS 2SS:"},
+};
+
 static int rtw89_get_rx_pkt_stat(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
                                 char *buf, size_t bufsz)
 {
@@ -4075,12 +4087,13 @@ static int rtw89_get_rx_pkt_stat(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *
                        continue;
 
                p += scnprintf(p, end - p, "%10s [", info->rate_mode);
-               p += rtw89_debug_append_rx_rate(p, end - p, pkt_stat,
-                                               first_rate, info->len);
+               p += rtw89_debug_append_rate(p, end - p, pkt_stat->rx_rate_cnt,
+                                            first_rate, info->len);
                if (info->ext) {
                        p += scnprintf(p, end - p, "][");
-                       p += rtw89_debug_append_rx_rate(p, end - p, pkt_stat,
-                                                       first_rate + info->len, info->ext);
+                       p += rtw89_debug_append_rate(p, end - p, pkt_stat->rx_rate_cnt,
+                                                    first_rate + info->len,
+                                                    info->ext);
                }
                p += scnprintf(p, end - p, "]\n");
        }
@@ -4125,6 +4138,87 @@ static ssize_t rtw89_debug_priv_phy_info_get(struct rtw89_dev *rtwdev,
        return p - buf;
 }
 
+static int rtw89_get_bb_stat(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
+                            char *buf, size_t bufsz)
+{
+       char *p = buf, *end = buf + bufsz;
+
+       p += scnprintf(p, end - p, "\n[PHY %u]\n", bb->phy_idx);
+
+       p += scnprintf(p, end - p, "== RSSI/RX Rate\n");
+       p += rtw89_get_rx_pkt_stat(rtwdev, bb, p, end - p);
+
+       return p - buf;
+}
+
+static ssize_t
+rtw89_debug_priv_bb_info_get(struct rtw89_dev *rtwdev,
+                            struct rtw89_debugfs_priv *debugfs_priv,
+                            char *buf, size_t bufsz)
+{
+       struct rtw89_bb_stat_cfg *bb_stat = &rtwdev->phy_info.bb_stat_cfg;
+       struct rtw89_traffic_stats *stats = &rtwdev->stats;
+       const struct rtw89_chip_info *chip = rtwdev->chip;
+       const struct rtw89_tx_rate_cnt_info *info;
+       struct rtw89_debugfs_iter_data iter_data;
+       char *p = buf, *end = buf + bufsz;
+       struct rtw89_bb_ctx *bb;
+       int i;
+
+       p += scnprintf(p, end - p, "TP TX: %u [%u] Mbps, RX: %u [%u] Mbps\n",
+                      stats->tx_throughput, stats->tx_throughput_raw,
+                      stats->rx_throughput, stats->rx_throughput_raw);
+       p += scnprintf(p, end - p, "Avg packet length: TX=%u, RX=%u\n",
+                      stats->tx_avg_len,
+                      stats->rx_avg_len);
+       p += scnprintf(p, end - p, "TF: %u\n", stats->rx_tf_periodic);
+
+       if (chip->chip_gen != RTW89_CHIP_AX) {
+               p += scnprintf(p, end - p,
+                              "TX count [0x%x]:\n", bb_stat->mac_id);
+
+               for (i = 0; i < ARRAY_SIZE(rtw89_tx_rate_cnt_infos); i++) {
+                       info = &rtw89_tx_rate_cnt_infos[i];
+
+                       p += scnprintf(p, end - p, "%10s [", info->rate_mode);
+                       p += rtw89_debug_append_rate(p, end - p,
+                                                    rtwdev->phystat.tx_rate_cnt,
+                                                    info->first_rate, info->len);
+                       p += scnprintf(p, end - p, "]\n");
+               }
+       }
+
+       rtw89_for_each_active_bb(rtwdev, bb)
+               p += rtw89_get_bb_stat(rtwdev, bb, p, end - p);
+       p += scnprintf(p, end - p, "\n");
+
+       rtw89_debugfs_iter_data_setup(&iter_data, p, end - p);
+       ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_sta_info_get_iter, &iter_data);
+       p += iter_data.written_sz;
+
+       return p - buf;
+}
+
+static ssize_t
+rtw89_debug_priv_bb_info_set(struct rtw89_dev *rtwdev,
+                            struct rtw89_debugfs_priv *debugfs_priv,
+                            const char *buf, size_t count)
+{
+       struct rtw89_bb_stat_cfg *bb_stat = &rtwdev->phy_info.bb_stat_cfg;
+       int val;
+
+       lockdep_assert_wiphy(rtwdev->hw->wiphy);
+
+       if (sscanf(buf, "enable %d", &val) == 1)
+               bb_stat->enable = !!val;
+       else if (sscanf(buf, "mac_id %x", &val) == 1)
+               rtw89_fw_h2c_tx_history(rtwdev, val);
+       else
+               return -EINVAL;
+
+       return count;
+}
+
 static int rtw89_dump_addr_cam(struct rtw89_dev *rtwdev,
                               char *buf, size_t bufsz,
                               struct rtw89_addr_cam_entry *addr_cam)
@@ -5000,6 +5094,7 @@ static const struct rtw89_debugfs rtw89_debugfs_templ = {
        .btc_manual = rtw89_debug_priv_set(btc_manual),
        .fw_log_manual = rtw89_debug_priv_set(fw_log_manual, WLOCK),
        .phy_info = rtw89_debug_priv_get(phy_info),
+       .bb_info = rtw89_debug_priv_set_and_get(bb_info, RWLOCK),
        .stations = rtw89_debug_priv_get(stations, RLOCK),
        .disable_dm = rtw89_debug_priv_set_and_get(disable_dm, RWLOCK),
        .static_pd_th = rtw89_debug_priv_set_and_get(static_pd_th, RWLOCK),
@@ -5049,6 +5144,7 @@ void rtw89_debugfs_add_sec1(struct rtw89_dev *rtwdev, struct dentry *debugfs_top
        rtw89_debugfs_add_w(btc_manual);
        rtw89_debugfs_add_w(fw_log_manual);
        rtw89_debugfs_add_r(phy_info);
+       rtw89_debugfs_add_rw(bb_info);
        rtw89_debugfs_add_r(stations);
        rtw89_debugfs_add_rw(disable_dm);
        rtw89_debugfs_add_rw(static_pd_th);
index 2a3662ed733f47219262bec909de24449b2d55ec..ff3914a16b81dd2d10f56fd539e370b2c49a646e 100644 (file)
@@ -930,6 +930,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
        __DIS_FW_FEAT(RTL8922A, ge, 0, 35, 84, 0, WITH_RFK_PRE_NOTIFY, G),
        __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 84, 0, RFK_PRE_NOTIFY_MCC_V1),
        __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 84, 0, ADDR_CAM_V0),
+       __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 92, 0, TX_HISTORY_V1),
        __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 97, 0, SIM_SER_L0L1_BY_HALT_H2C),
        __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 100, 0, SER_POST_RECOVER_DMAC),
 };
@@ -5588,6 +5589,127 @@ fail:
        return ret;
 }
 
+int rtw89_fw_h2c_tx_history(struct rtw89_dev *rtwdev, u16 mac_id)
+{
+       struct rtw89_bb_stat_cfg *bb_stat = &rtwdev->phy_info.bb_stat_cfg;
+       const struct rtw89_chip_info *chip = rtwdev->chip;
+       struct rtw89_h2c_ra_tx_history *h2c;
+       u32 len = sizeof(*h2c);
+       struct sk_buff *skb;
+       int ret;
+
+       if (chip->chip_gen == RTW89_CHIP_AX)
+               return 0;
+
+       skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+       if (!skb) {
+               rtw89_err(rtwdev, "failed to alloc skb for h2c tx history\n");
+               return -ENOMEM;
+       }
+
+       skb_put(skb, len);
+       h2c = (struct rtw89_h2c_ra_tx_history *)skb->data;
+
+       h2c->w0 = le32_encode_bits(mac_id, RTW89_H2C_RA_TX_HISTORY_W0_MACID) |
+                 le32_encode_bits(0, RTW89_H2C_RA_TX_HISTORY_W0_PER_PPDU);
+
+       rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+                             H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RA,
+                             H2C_FUNC_OUTSRC_RA_TX_HISTORY, 0, 0, len);
+
+       ret = rtw89_h2c_tx(rtwdev, skb, false);
+       if (ret) {
+               rtw89_err(rtwdev, "failed to send h2c\n");
+               goto fail;
+       }
+
+       bb_stat->mac_id = mac_id;
+
+       return 0;
+fail:
+       dev_kfree_skb_any(skb);
+
+       return ret;
+}
+
+int rtw89_fw_h2c_phy_ch_rpt(struct rtw89_dev *rtwdev)
+{
+       const struct rtw89_chip_info *chip = rtwdev->chip;
+       struct rtw89_h2c_ra_phy_ch_rpt *h2c;
+       u32 len = sizeof(*h2c);
+       struct sk_buff *skb;
+       int ret;
+
+       if (chip->chip_gen == RTW89_CHIP_AX)
+               return 0;
+
+       skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+       if (!skb) {
+               rtw89_err(rtwdev, "failed to alloc skb for h2c phy ch rpt\n");
+               return -ENOMEM;
+       }
+
+       skb_put(skb, len);
+       h2c = (struct rtw89_h2c_ra_phy_ch_rpt *)skb->data;
+
+       h2c->w1 = le32_encode_bits(1, RTW89_H2C_RA_PHY_CH_RPT_W1_RPT_TX_COUNT);
+
+       rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+                             H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RA,
+                             H2C_FUNC_OUTSRC_RA_PHY_CH_RPT, 0, 0, len);
+
+       ret = rtw89_h2c_tx(rtwdev, skb, false);
+       if (ret) {
+               rtw89_err(rtwdev, "failed to send h2c\n");
+               goto fail;
+       }
+
+       return 0;
+fail:
+       dev_kfree_skb_any(skb);
+
+       return ret;
+}
+
+int rtw89_fw_h2c_drv_ctrl_fw(struct rtw89_dev *rtwdev)
+{
+       const struct rtw89_chip_info *chip = rtwdev->chip;
+       struct rtw89_h2c_ra_drv_ctrl_fw *h2c;
+       u32 len = sizeof(*h2c);
+       struct sk_buff *skb;
+       int ret;
+
+       if (chip->chip_gen == RTW89_CHIP_AX)
+               return 0;
+
+       skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+       if (!skb) {
+               rtw89_err(rtwdev, "failed to alloc skb for h2c drv ctrl fw\n");
+               return -ENOMEM;
+       }
+
+       skb_put(skb, len);
+       h2c = (struct rtw89_h2c_ra_drv_ctrl_fw *)skb->data;
+
+       h2c->w0 = le32_encode_bits(1, RTW89_H2C_RA_DRV_CTRL_FW_W0_RPT_TX_COUNT);
+
+       rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+                             H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RA,
+                             H2C_FUNC_OUTSRC_RA_DRV_CTRL_FW, 0, 0, len);
+
+       ret = rtw89_h2c_tx(rtwdev, skb, false);
+       if (ret) {
+               rtw89_err(rtwdev, "failed to send h2c\n");
+               goto fail;
+       }
+
+       return 0;
+fail:
+       dev_kfree_skb_any(skb);
+
+       return ret;
+}
+
 int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type)
 {
        struct rtw89_btc *btc = &rtwdev->btc;
index 6ef53fcd0ccef31372969253883a589cd84aa17e..cde8fd34723b96476f84c4c6ec273f012c0f7a8b 100644 (file)
@@ -471,6 +471,28 @@ struct rtw89_h2c_ra_v1 {
 #define RTW89_H2C_RA_V1_W4_RAMASK_UHL16 GENMASK(31, 16)
 #define RTW89_H2C_RA_V1_W5_RAMASK_UHH16 GENMASK(15, 0)
 
+struct rtw89_h2c_ra_tx_history {
+       __le32 w0;
+} __packed;
+
+#define RTW89_H2C_RA_TX_HISTORY_W0_MACID GENMASK(15, 0)
+#define RTW89_H2C_RA_TX_HISTORY_W0_PER_PPDU GENMASK(23, 16)
+
+struct rtw89_h2c_ra_phy_ch_rpt {
+       __le32 w0;
+       __le32 w1;
+       __le32 w2;
+       __le32 w3;
+} __packed;
+
+#define RTW89_H2C_RA_PHY_CH_RPT_W1_RPT_TX_COUNT BIT(10)
+
+struct rtw89_h2c_ra_drv_ctrl_fw {
+       __le32 w0;
+} __packed;
+
+#define RTW89_H2C_RA_DRV_CTRL_FW_W0_RPT_TX_COUNT BIT(13)
+
 static inline void RTW89_SET_FWCMD_SEC_IDX(void *cmd, u32 val)
 {
        le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(7, 0));
@@ -3973,6 +3995,13 @@ struct rtw89_c2h_lps_rpt {
         */
 } __packed;
 
+struct rtw89_c2h_ra_tx_history {
+       struct rtw89_c2h_hdr hdr;
+       __le32 ra_tbtt_cnt;
+       __le32 tx_rate_tot_cnt_hist[RTW89_TX_RATE_NR];
+       __le32 tx_cat_cnt[3];
+} __packed;
+
 struct rtw89_c2h_fw_scan_rpt {
        struct rtw89_c2h_hdr hdr;
        u8 phy_idx;
@@ -4771,6 +4800,9 @@ enum rtw89_mrc_h2c_func {
 
 #define H2C_CL_OUTSRC_RA               0x1
 #define H2C_FUNC_OUTSRC_RA_MACIDCFG    0x0
+#define H2C_FUNC_OUTSRC_RA_TX_HISTORY  0x9
+#define H2C_FUNC_OUTSRC_RA_PHY_CH_RPT  0xe
+#define H2C_FUNC_OUTSRC_RA_DRV_CTRL_FW 0xf
 
 #define H2C_CL_OUTSRC_DM               0x2
 #define H2C_FUNC_FW_MCC_DIG            0x6
@@ -5349,6 +5381,9 @@ int rtw89_fw_h2c_rssi_offload(struct rtw89_dev *rtwdev,
                              struct rtw89_rx_phy_ppdu *phy_ppdu);
 int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
 int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi);
+int rtw89_fw_h2c_phy_ch_rpt(struct rtw89_dev *rtwdev);
+int rtw89_fw_h2c_tx_history(struct rtw89_dev *rtwdev, u16 mac_id);
+int rtw89_fw_h2c_drv_ctrl_fw(struct rtw89_dev *rtwdev);
 int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev, u8 type);
index 9ee2aa225976d7dc173334e2473c58ac9915748f..b72f6661fbd1a76e3c6a68ff121adcdba5d5514d 100644 (file)
@@ -721,14 +721,21 @@ static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw,
 
        if (changed & BSS_CHANGED_MLD_VALID_LINKS) {
                struct rtw89_vif_link *cur = rtw89_get_designated_link(rtwvif);
+               u16 mac_id;
 
                if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw))
                        rtw89_chip_rfk_channel(rtwdev, cur);
 
-               if (hweight16(vif->active_links) == 1)
+               if (hweight16(vif->active_links) == 1) {
+                       mac_id = cur->mac_id;
                        rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR;
-               else
+               } else {
+                       /* Specify for all MAC ID */
+                       mac_id = 0xffff;
                        rtwvif->mlo_mode = RTW89_MLO_MODE_EMLSR;
+               }
+
+               rtw89_fw_h2c_tx_history(rtwdev, mac_id);
        }
 }
 
index 29770cc5ea60a51c0e6598a3089f7fcfbaf6dc6e..3124a99d538111da0d935682187418ef98f41ca1 100644 (file)
@@ -3379,12 +3379,24 @@ rtw89_phy_c2h_ra_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
                                          &ra_data);
 }
 
+static void
+rtw89_phy_c2h_tx_history(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+       const struct rtw89_c2h_ra_tx_history *history = (const void *)c2h->data;
+       u32 *tx_rate_cnt = rtwdev->phystat.tx_rate_cnt;
+       u32 i;
+
+       for (i = 0; i < RTW89_TX_RATE_NR; i++)
+               tx_rate_cnt[i] = le32_to_cpu(history->tx_rate_tot_cnt_hist[i]);
+}
+
 static
 void (* const rtw89_phy_c2h_ra_handler[])(struct rtw89_dev *rtwdev,
                                          struct sk_buff *c2h, u32 len) = {
        [RTW89_PHY_C2H_FUNC_STS_RPT] = rtw89_phy_c2h_ra_rpt,
        [RTW89_PHY_C2H_FUNC_MU_GPTBL_RPT] = NULL,
        [RTW89_PHY_C2H_FUNC_TXSTS] = NULL,
+       [RTW89_PHY_C2H_FUNC_TX_HISTORY] = rtw89_phy_c2h_tx_history,
        [RTW89_PHY_C2H_FUNC_ACCELERATE_EN] = rtw89_fw_c2h_dummy_handler,
 };
 
@@ -5832,6 +5844,22 @@ static void rtw89_phy_stat_init(struct rtw89_dev *rtwdev)
        rtwdev->hal.thermal_prot_lv = 0;
 }
 
+static void rtw89_phy_trigger_tx_count(struct rtw89_dev *rtwdev)
+{
+       if (RTW89_CHK_FW_FEATURE(TX_HISTORY_V1, &rtwdev->fw))
+               rtw89_fw_h2c_phy_ch_rpt(rtwdev);
+       else
+               rtw89_fw_h2c_drv_ctrl_fw(rtwdev);
+}
+
+static void rtw89_phy_stat_update(struct rtw89_dev *rtwdev)
+{
+       if (!rtwdev->phy_info.bb_stat_cfg.enable)
+               return;
+
+       rtw89_phy_trigger_tx_count(rtwdev);
+}
+
 void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
 {
        struct rtw89_bb_ctx *bb;
@@ -5839,6 +5867,7 @@ void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
        rtw89_phy_stat_thermal_update(rtwdev);
        rtw89_phy_thermal_protect(rtwdev);
        rtw89_phy_stat_rssi_update(rtwdev);
+       rtw89_phy_stat_update(rtwdev);
 
        rtw89_for_each_active_bb(rtwdev, bb) {
                bb->last_pkt_stat = bb->cur_pkt_stat;
index 3f9d306ff1cacf8dc9f50fee9bef3706288d0001..c6761cedc5a5c35f1f677a4575151b59366f9cee 100644 (file)
@@ -139,6 +139,7 @@ enum rtw89_phy_c2h_ra_func {
        RTW89_PHY_C2H_FUNC_STS_RPT,
        RTW89_PHY_C2H_FUNC_MU_GPTBL_RPT,
        RTW89_PHY_C2H_FUNC_TXSTS,
+       RTW89_PHY_C2H_FUNC_TX_HISTORY = 0x4,
        RTW89_PHY_C2H_FUNC_ACCELERATE_EN = 0x7,
 
        RTW89_PHY_C2H_FUNC_RA_NUM,