From: Ping-Ke Shih <pkshih@realtek.com>
To: <linux-wireless@vger.kernel.org>
Cc: <damon.chen@realtek.com>
Subject: [PATCH rtw-next 3/7] wifi: rtw89: debug: bb_info entry including TX rate count for WiFi 7 chips
Date: Wed, 29 Apr 2026 21:26:21 +0800 [thread overview]
Message-ID: <20260429132625.1659182-4-pkshih@realtek.com> (raw)
In-Reply-To: <20260429132625.1659182-1-pkshih@realtek.com>
From: Kuan-Chung Chen <damon.chen@realtek.com>
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>
---
drivers/net/wireless/realtek/rtw89/core.c | 2 +
drivers/net/wireless/realtek/rtw89/core.h | 13 ++
drivers/net/wireless/realtek/rtw89/debug.c | 110 +++++++++++++++-
drivers/net/wireless/realtek/rtw89/fw.c | 122 ++++++++++++++++++
drivers/net/wireless/realtek/rtw89/fw.h | 35 +++++
drivers/net/wireless/realtek/rtw89/mac80211.c | 11 +-
drivers/net/wireless/realtek/rtw89/phy.c | 29 +++++
drivers/net/wireless/realtek/rtw89/phy.h | 1 +
8 files changed, 314 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 81f3ae21dc18..d8f83623e54a 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -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:
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index f15a0c43ef6d..c4396f0100be 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -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;
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index 2d953bec149b..b82b13645fb0 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -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);
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 2a3662ed733f..ff3914a16b81 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -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 @@ int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi
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;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 6ef53fcd0cce..cde8fd34723b 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -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);
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 9ee2aa225976..b72f6661fbd1 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -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);
}
}
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 29770cc5ea60..3124a99d5381 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -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;
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index 3f9d306ff1ca..c6761cedc5a5 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -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,
--
2.25.1
next prev parent reply other threads:[~2026-04-29 13:26 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-29 13:26 [PATCH rtw-next 0/7] wifi: rtw89: debug: introduce BB diagnosis Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 1/7] wifi: rtw89: mlo: rearrange MLSR link decision flow Ping-Ke Shih
2026-05-06 8:23 ` Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 2/7] wifi: rtw89: phy: support per PHY RX statistics Ping-Ke Shih
2026-04-29 13:26 ` Ping-Ke Shih [this message]
2026-04-29 13:26 ` [PATCH rtw-next 4/7] wifi: rtw89: debug: add PMAC counter in bb_info Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 5/7] wifi: rtw89: debug: extend bb_info with TX status and PER Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 6/7] wifi: rtw89: debug: add RX statistics in bb_info Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 7/7] wifi: rtw89: debug: add BB diagnose Ping-Ke Shih
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260429132625.1659182-4-pkshih@realtek.com \
--to=pkshih@realtek.com \
--cc=damon.chen@realtek.com \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox