* [PATCH rtw-next 1/7] wifi: rtw89: mlo: rearrange MLSR link decision flow
2026-04-29 13:26 [PATCH rtw-next 0/7] wifi: rtw89: debug: introduce BB diagnosis Ping-Ke Shih
@ 2026-04-29 13:26 ` 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
` (5 subsequent siblings)
6 siblings, 1 reply; 9+ messages in thread
From: Ping-Ke Shih @ 2026-04-29 13:26 UTC (permalink / raw)
To: linux-wireless; +Cc: damon.chen
From: Kuan-Chung Chen <damon.chen@realtek.com>
The original MLSR link decision refers to RSSI, but it should be
based on the premise of an existing link. Otherwise, make a link
decision to select a new link from any available band.
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 | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 7e058c071cc4..03d80d012022 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -4746,13 +4746,19 @@ static void rtw89_core_mlsr_link_decision(struct rtw89_dev *rtwdev,
{
unsigned int sel_link_id = IEEE80211_MLD_MAX_NUM_LINKS;
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ u8 decided_bands = BIT(RTW89_BAND_NUM) - 1;
struct rtw89_vif_link *rtwvif_link;
const struct rtw89_chan *chan;
unsigned long usable_links;
unsigned int link_id;
- u8 decided_bands;
u8 rssi;
+ usable_links = ieee80211_vif_usable_links(vif);
+
+ rtwvif_link = rtw89_get_designated_link(rtwvif);
+ if (unlikely(!rtwvif_link))
+ goto select;
+
rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi);
if (unlikely(!rssi))
return;
@@ -4764,12 +4770,6 @@ static void rtw89_core_mlsr_link_decision(struct rtw89_dev *rtwdev,
else
return;
- usable_links = ieee80211_vif_usable_links(vif);
-
- rtwvif_link = rtw89_get_designated_link(rtwvif);
- if (unlikely(!rtwvif_link))
- goto select;
-
chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
if (decided_bands & BIT(chan->band_type))
return;
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH rtw-next 1/7] wifi: rtw89: mlo: rearrange MLSR link decision flow
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
0 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-05-06 8:23 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless; +Cc: damon.chen
Ping-Ke Shih <pkshih@realtek.com> wrote:
> From: Kuan-Chung Chen <damon.chen@realtek.com>
>
> The original MLSR link decision refers to RSSI, but it should be
> based on the premise of an existing link. Otherwise, make a link
> decision to select a new link from any available band.
>
> Signed-off-by: Kuan-Chung Chen <damon.chen@realtek.com>
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
7 patch(es) applied to rtw-next branch of rtw.git, thanks.
7284f5be5d29 wifi: rtw89: mlo: rearrange MLSR link decision flow
09d369c66373 wifi: rtw89: phy: support per PHY RX statistics
523d012f47e7 wifi: rtw89: debug: bb_info entry including TX rate count for WiFi 7 chips
3b851f36c3f1 wifi: rtw89: debug: add PMAC counter in bb_info
419ed7f4a053 wifi: rtw89: debug: extend bb_info with TX status and PER
c77bb66e244e wifi: rtw89: debug: add RX statistics in bb_info
c1ed02655f91 wifi: rtw89: debug: add BB diagnose
---
https://github.com/pkshih/rtw.git
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH rtw-next 2/7] wifi: rtw89: phy: support per PHY RX statistics
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-04-29 13:26 ` Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 3/7] wifi: rtw89: debug: bb_info entry including TX rate count for WiFi 7 chips Ping-Ke Shih
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-04-29 13:26 UTC (permalink / raw)
To: linux-wireless; +Cc: damon.chen
From: Kuan-Chung Chen <damon.chen@realtek.com>
Previously, RX statistics such as beacon RSSI and packet
counters were shared across all PHYs. To support MLO,
extend the statistics to be maintained per PHY.
Update the debugfs output for phy_info and beacon_info
to include a "[PHY X]" label for better clarity.
The output of phy_info:
TP TX: 0 [0] Mbps (lv: 0), RX: 0 [0] Mbps (lv: 0)
Avg packet length: TX=0, RX=120
TF: 0
[PHY 0]
Beacon: 19 (-45 dBm)
RX count:
Legacy: [0, 0, 0, 0]
...
EHT 2SS: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
The output of beacon_info:
[PHY 0]
Beacon: 20
raw rssi: 131
hw rate: 4
length: 437
[Beacon info]
interval: 100
dtim: 1
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 | 26 ++++--
drivers/net/wireless/realtek/rtw89/core.h | 6 +-
drivers/net/wireless/realtek/rtw89/debug.c | 88 ++++++++++++-------
drivers/net/wireless/realtek/rtw89/fw.c | 6 +-
drivers/net/wireless/realtek/rtw89/phy.c | 17 ++--
drivers/net/wireless/realtek/rtw89/rtw8852a.c | 5 +-
6 files changed, 97 insertions(+), 51 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 03d80d012022..81f3ae21dc18 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -2736,12 +2736,14 @@ static u16 rtw89_bcn_get_histogram_bound(struct rtw89_dev *rtwdev, u8 target)
}
static u16 rtw89_bcn_get_rx_time(struct rtw89_dev *rtwdev,
- const struct rtw89_chan *chan)
+ struct rtw89_vif_link *rtwvif_link)
{
#define RTW89_SYMBOL_TIME_2GHZ 192
#define RTW89_SYMBOL_TIME_5GHZ 20
#define RTW89_SYMBOL_TIME_6GHZ 20
- struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat;
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
+ struct rtw89_bb_ctx *bb = rtw89_get_bb_ctx(rtwdev, rtwvif_link->phy_idx);
+ struct rtw89_pkt_stat *pkt_stat = &bb->cur_pkt_stat;
u16 bitrate, val;
if (!rtw89_legacy_rate_to_bitrate(rtwdev, pkt_stat->beacon_rate, &bitrate))
@@ -2772,15 +2774,15 @@ static void rtw89_bcn_calc_timeout(struct rtw89_dev *rtwdev,
#define RTW89_BCN_TRACK_EXTEND_TIMEOUT 5
#define RTW89_BCN_TRACK_COVERAGE_TH 0 /* unit: TU */
#define RTW89_BCN_TRACK_STRONG_RSSI 80
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
- struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat;
+ struct rtw89_bb_ctx *bb = rtw89_get_bb_ctx(rtwdev, rtwvif_link->phy_idx);
struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
+ struct rtw89_pkt_stat *pkt_stat = &bb->cur_pkt_stat;
struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist;
u16 outlier_high_bcn_th = bcn_track->outlier_high_bcn_th;
u16 outlier_low_bcn_th = bcn_track->outlier_low_bcn_th;
- u8 rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi);
u16 target_bcn_th = bcn_track->target_bcn_th;
+ u8 rssi = ewma_rssi_read(&bb->bcn_rssi);
u16 low_bcn_th = bcn_track->low_bcn_th;
u16 med_bcn_th = bcn_track->med_bcn_th;
u16 beacon_int = bcn_track->beacon_int;
@@ -2826,7 +2828,7 @@ static void rtw89_bcn_calc_timeout(struct rtw89_dev *rtwdev,
bcn_timeout = bcn_stat->drift[target_bcn_th];
out:
- bcn_track->bcn_timeout = bcn_timeout + rtw89_bcn_get_rx_time(rtwdev, chan);
+ bcn_track->bcn_timeout = bcn_timeout + rtw89_bcn_get_rx_time(rtwdev, rtwvif_link);
}
static void rtw89_bcn_update_timeout(struct rtw89_dev *rtwdev,
@@ -2987,7 +2989,6 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
struct rtw89_vif_rx_stats_iter_data *iter_data = data;
struct rtw89_dev *rtwdev = iter_data->rtwdev;
struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
- struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat;
struct rtw89_rx_desc_info *desc_info = iter_data->desc_info;
struct sk_buff *skb = iter_data->skb;
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
@@ -2997,6 +2998,8 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
struct ieee80211_bss_conf *bss_conf;
struct rtw89_vif_link *rtwvif_link;
const u8 *bssid = iter_data->bssid;
+ struct rtw89_pkt_stat *pkt_stat;
+ struct rtw89_bb_ctx *bb;
const u8 *target_bssid;
if (rtwdev->scanning &&
@@ -3030,6 +3033,9 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
rx_status->link_id = rtwvif_link->link_id;
}
+ bb = rtw89_get_bb_ctx(rtwdev, rtwvif_link->phy_idx);
+ pkt_stat = &bb->cur_pkt_stat;
+
if (ieee80211_is_beacon(hdr->frame_control)) {
if (vif->type == NL80211_IFTYPE_STATION &&
!test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) {
@@ -3038,7 +3044,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
}
if (phy_ppdu) {
- ewma_rssi_add(&rtwdev->phystat.bcn_rssi, phy_ppdu->rssi_avg);
+ ewma_rssi_add(&bb->bcn_rssi, phy_ppdu->rssi_avg);
if (!test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
rtwvif_link->bcn_bw_idx = phy_ppdu->bw_idx;
}
@@ -4750,6 +4756,7 @@ static void rtw89_core_mlsr_link_decision(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link;
const struct rtw89_chan *chan;
unsigned long usable_links;
+ struct rtw89_bb_ctx *bb;
unsigned int link_id;
u8 rssi;
@@ -4759,7 +4766,8 @@ static void rtw89_core_mlsr_link_decision(struct rtw89_dev *rtwdev,
if (unlikely(!rtwvif_link))
goto select;
- rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi);
+ bb = rtw89_get_bb_ctx(rtwdev, rtwvif_link->phy_idx);
+ rssi = ewma_rssi_read(&bb->bcn_rssi);
if (unlikely(!rssi))
return;
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index b290da650c70..f15a0c43ef6d 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -5345,9 +5345,6 @@ DECLARE_EWMA(thermal, 4, 4);
struct rtw89_phy_stat {
struct ewma_thermal avg_thermal[RF_PATH_MAX];
u8 last_thermal_max;
- struct ewma_rssi bcn_rssi;
- struct rtw89_pkt_stat cur_pkt_stat;
- struct rtw89_pkt_stat last_pkt_stat;
struct rtw89_beacon_stat bcn_stat;
};
@@ -6318,6 +6315,9 @@ struct rtw89_dev {
struct rtw89_dig_info dig;
struct rtw89_phy_ch_info ch_info;
struct rtw89_edcca_bak edcca_bak;
+ struct ewma_rssi bcn_rssi;
+ struct rtw89_pkt_stat cur_pkt_stat;
+ struct rtw89_pkt_stat last_pkt_stat;
} bbs[RTW89_PHY_NUM];
struct wiphy_delayed_work track_work;
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index 2cb6e441b2f8..2d953bec149b 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -4051,38 +4051,20 @@ static const struct rtw89_rx_rate_cnt_info {
{FIRST_RATE_GEV1(EHT_NSS2_MCS0), 14, 0, "EHT 2SS:"},
};
-static ssize_t rtw89_debug_priv_phy_info_get(struct rtw89_dev *rtwdev,
- struct rtw89_debugfs_priv *debugfs_priv,
- char *buf, size_t bufsz)
+static int rtw89_get_rx_pkt_stat(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
+ char *buf, size_t bufsz)
{
- struct rtw89_traffic_stats *stats = &rtwdev->stats;
- struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.last_pkt_stat;
+ struct rtw89_pkt_stat *pkt_stat = &bb->last_pkt_stat;
const struct rtw89_chip_info *chip = rtwdev->chip;
- struct rtw89_debugfs_iter_data iter_data;
const struct rtw89_rx_rate_cnt_info *info;
- struct rtw89_hal *hal = &rtwdev->hal;
+ u8 rssi = ewma_rssi_read(&bb->bcn_rssi);
char *p = buf, *end = buf + bufsz;
enum rtw89_hw_rate first_rate;
- u8 rssi;
int i;
- rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi);
-
- p += scnprintf(p, end - p, "TP TX: %u [%u] Mbps (lv: %d",
- stats->tx_throughput, stats->tx_throughput_raw,
- stats->tx_tfc_lv);
- if (hal->thermal_prot_lv)
- p += scnprintf(p, end - p, ", duty: %d%%",
- 100 - hal->thermal_prot_lv * RTW89_THERMAL_PROT_STEP);
- p += scnprintf(p, end - p, "), RX: %u [%u] Mbps (lv: %d)\n",
- stats->rx_throughput, stats->rx_throughput_raw,
- stats->rx_tfc_lv);
- p += scnprintf(p, end - p, "Beacon: %u (%d dBm), TF: %u\n",
+ p += scnprintf(p, end - p, "Beacon: %u (%d dBm)\n",
pkt_stat->beacon_nr,
- RTW89_RSSI_RAW_TO_DBM(rssi), stats->rx_tf_periodic);
- p += scnprintf(p, end - p, "Avg packet length: TX=%u, RX=%u\n",
- stats->tx_avg_len,
- stats->rx_avg_len);
+ RTW89_RSSI_RAW_TO_DBM(rssi));
p += scnprintf(p, end - p, "RX count:\n");
@@ -4103,6 +4085,39 @@ static ssize_t rtw89_debug_priv_phy_info_get(struct rtw89_dev *rtwdev,
p += scnprintf(p, end - p, "]\n");
}
+ return p - buf;
+}
+
+static ssize_t rtw89_debug_priv_phy_info_get(struct rtw89_dev *rtwdev,
+ struct rtw89_debugfs_priv *debugfs_priv,
+ char *buf, size_t bufsz)
+{
+ struct rtw89_traffic_stats *stats = &rtwdev->stats;
+ struct rtw89_debugfs_iter_data iter_data;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ char *p = buf, *end = buf + bufsz;
+ struct rtw89_bb_ctx *bb;
+
+ p += scnprintf(p, end - p, "TP TX: %u [%u] Mbps (lv: %d",
+ stats->tx_throughput, stats->tx_throughput_raw,
+ stats->tx_tfc_lv);
+ if (hal->thermal_prot_lv)
+ p += scnprintf(p, end - p, ", duty: %d%%",
+ 100 - hal->thermal_prot_lv * RTW89_THERMAL_PROT_STEP);
+ p += scnprintf(p, end - p, "), RX: %u [%u] Mbps (lv: %d)\n",
+ stats->rx_throughput, stats->rx_throughput_raw,
+ stats->rx_tfc_lv);
+ 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);
+
+ rtw89_for_each_active_bb(rtwdev, bb) {
+ p += scnprintf(p, end - p, "\n[PHY %u]\n", bb->phy_idx);
+ p += rtw89_get_rx_pkt_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;
@@ -4858,12 +4873,26 @@ rtw89_debug_priv_diag_mac_get(struct rtw89_dev *rtwdev,
return rtw89_mac_diag_iter_all(rtwdev, buf, bufsz);
}
+static int rtw89_get_beacon_info(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
+ char *buf, size_t bufsz)
+{
+ struct rtw89_pkt_stat *pkt_stat = &bb->last_pkt_stat;
+ char *p = buf, *end = buf + bufsz;
+
+ p += scnprintf(p, end - p, "[PHY %u]\n", bb->phy_idx);
+ p += scnprintf(p, end - p, "Beacon: %u\n", pkt_stat->beacon_nr);
+ p += scnprintf(p, end - p, "raw rssi: %lu\n", ewma_rssi_read(&bb->bcn_rssi));
+ p += scnprintf(p, end - p, "hw rate: %u\n", pkt_stat->beacon_rate);
+ p += scnprintf(p, end - p, "length: %u\n\n", pkt_stat->beacon_len);
+
+ return p - buf;
+}
+
static ssize_t
rtw89_debug_priv_beacon_info_get(struct rtw89_dev *rtwdev,
struct rtw89_debugfs_priv *debugfs_priv,
char *buf, size_t bufsz)
{
- struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.last_pkt_stat;
struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist;
@@ -4871,17 +4900,16 @@ rtw89_debug_priv_beacon_info_get(struct rtw89_dev *rtwdev,
char *p = buf, *end = buf + bufsz;
u16 *drift = bcn_stat->drift;
u8 bcn_num = bcn_stat->num;
+ struct rtw89_bb_ctx *bb;
u8 count;
u8 i;
+ rtw89_for_each_active_bb(rtwdev, bb)
+ p += rtw89_get_beacon_info(rtwdev, bb, p, end - p);
+
p += scnprintf(p, end - p, "[Beacon info]\n");
- p += scnprintf(p, end - p, "count: %u\n", pkt_stat->beacon_nr);
p += scnprintf(p, end - p, "interval: %u\n", bcn_track->beacon_int);
p += scnprintf(p, end - p, "dtim: %u\n", bcn_track->dtim);
- p += scnprintf(p, end - p, "raw rssi: %lu\n",
- ewma_rssi_read(&rtwdev->phystat.bcn_rssi));
- p += scnprintf(p, end - p, "hw rate: %u\n", pkt_stat->beacon_rate);
- p += scnprintf(p, end - p, "length: %u\n", pkt_stat->beacon_len);
p += scnprintf(p, end - p, "\n[Distribution]\n");
p += scnprintf(p, end - p, "tbtt\n");
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index b5d2540cf212..2a3662ed733f 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -3223,14 +3223,15 @@ int rtw89_fw_h2c_lps_ml_cmn_info(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif)
{
const struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be;
- struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat;
static const u8 bcn_bw_ofst[] = {0, 0, 0, 3, 6, 9, 0, 12};
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_efuse *efuse = &rtwdev->efuse;
struct rtw89_h2c_lps_ml_cmn_info *h2c;
struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_pkt_stat *pkt_stat;
const struct rtw89_chan *chan;
u8 bw_idx = RTW89_BB_BW_20_40;
+ struct rtw89_bb_ctx *bb;
u32 len = sizeof(*h2c);
unsigned int link_id;
struct sk_buff *skb;
@@ -3261,11 +3262,14 @@ int rtw89_fw_h2c_lps_ml_cmn_info(struct rtw89_dev *rtwdev,
path = rtwvif_link->phy_idx == RTW89_PHY_1 ? RF_PATH_B : RF_PATH_A;
chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
gain_band = rtw89_subband_to_gain_band_be(chan->subband_type);
+ bb = rtw89_get_bb_ctx(rtwdev, rtwvif_link->phy_idx);
h2c->central_ch[rtwvif_link->phy_idx] = chan->channel;
h2c->pri_ch[rtwvif_link->phy_idx] = chan->primary_channel;
h2c->band[rtwvif_link->phy_idx] = chan->band_type;
h2c->bw[rtwvif_link->phy_idx] = chan->band_width;
+
+ pkt_stat = &bb->cur_pkt_stat;
if (pkt_stat->beacon_rate < RTW89_HW_RATE_OFDM6)
h2c->bcn_rate_type[rtwvif_link->phy_idx] = 0x1;
else
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 95b5ace2a27e..29770cc5ea60 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -5814,6 +5814,7 @@ static void rtw89_phy_stat_rssi_update(struct rtw89_dev *rtwdev)
static void rtw89_phy_stat_init(struct rtw89_dev *rtwdev)
{
struct rtw89_phy_stat *phystat = &rtwdev->phystat;
+ struct rtw89_bb_ctx *bb;
int i;
for (i = 0; i < rtwdev->chip->rf_path_num; i++)
@@ -5821,24 +5822,28 @@ static void rtw89_phy_stat_init(struct rtw89_dev *rtwdev)
rtw89_phy_stat_thermal_update(rtwdev);
- memset(&phystat->cur_pkt_stat, 0, sizeof(phystat->cur_pkt_stat));
- memset(&phystat->last_pkt_stat, 0, sizeof(phystat->last_pkt_stat));
+ rtw89_for_each_capab_bb(rtwdev, bb) {
+ memset(&bb->cur_pkt_stat, 0, sizeof(bb->cur_pkt_stat));
+ memset(&bb->last_pkt_stat, 0, sizeof(bb->last_pkt_stat));
- ewma_rssi_init(&phystat->bcn_rssi);
+ ewma_rssi_init(&bb->bcn_rssi);
+ }
rtwdev->hal.thermal_prot_lv = 0;
}
void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
{
- struct rtw89_phy_stat *phystat = &rtwdev->phystat;
+ struct rtw89_bb_ctx *bb;
rtw89_phy_stat_thermal_update(rtwdev);
rtw89_phy_thermal_protect(rtwdev);
rtw89_phy_stat_rssi_update(rtwdev);
- phystat->last_pkt_stat = phystat->cur_pkt_stat;
- memset(&phystat->cur_pkt_stat, 0, sizeof(phystat->cur_pkt_stat));
+ rtw89_for_each_active_bb(rtwdev, bb) {
+ bb->last_pkt_stat = bb->cur_pkt_stat;
+ memset(&bb->cur_pkt_stat, 0, sizeof(bb->cur_pkt_stat));
+ }
}
static u16 rtw89_phy_ccx_us_to_idx(struct rtw89_dev *rtwdev,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index 9cd4c88ee57e..b81eeb59be60 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -2158,13 +2158,14 @@ static void rtw8852a_query_ppdu(struct rtw89_dev *rtwdev,
struct rtw89_rx_phy_ppdu *phy_ppdu,
struct ieee80211_rx_status *status)
{
- u8 path;
+ struct rtw89_bb_ctx *bb = rtw89_get_bb_ctx(rtwdev, phy_ppdu->phy_idx);
u8 *rx_power = phy_ppdu->rssi;
+ u8 path;
u8 raw;
if (!status->signal) {
if (phy_ppdu->to_self)
- raw = ewma_rssi_read(&rtwdev->phystat.bcn_rssi);
+ raw = ewma_rssi_read(&bb->bcn_rssi);
else
raw = max(rx_power[RF_PATH_A], rx_power[RF_PATH_B]);
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH rtw-next 3/7] wifi: rtw89: debug: bb_info entry including TX rate count for WiFi 7 chips
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-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
2026-04-29 13:26 ` [PATCH rtw-next 4/7] wifi: rtw89: debug: add PMAC counter in bb_info Ping-Ke Shih
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-04-29 13:26 UTC (permalink / raw)
To: linux-wireless; +Cc: damon.chen
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
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH rtw-next 4/7] wifi: rtw89: debug: add PMAC counter in bb_info
2026-04-29 13:26 [PATCH rtw-next 0/7] wifi: rtw89: debug: introduce BB diagnosis Ping-Ke Shih
` (2 preceding siblings ...)
2026-04-29 13:26 ` [PATCH rtw-next 3/7] wifi: rtw89: debug: bb_info entry including TX rate count for WiFi 7 chips Ping-Ke Shih
@ 2026-04-29 13:26 ` 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
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-04-29 13:26 UTC (permalink / raw)
To: linux-wireless; +Cc: damon.chen
From: Kuan-Chung Chen <damon.chen@realtek.com>
PMAC (Pseudo MAC) is a circuit within the baseband that can report
various packet-related counters through registers, such as TX ON,
TX EN, CCA, FA, CRC, etc. The driver periodically collects per
PHY PMAC counters in track_work and exposes them through the
bb_info debugfs for easier debugging.
The output of PMAC counter:
== PMAC
TX [CCK_TXEN, CCK_TXON, OFDM_TXEN, OFDM_TXON]: [0, 0, 17, 17]
CRC [CCK, OFDM, HT, VHT, HE, EHT, ALL, MPDU]
ok: [0, 301, 0, 0, 5, 0, 306, 5]
err: [0, 4, 0, 0, 0, 0, 4, 0]
CCA [CCK, OFDM]: [0, 353]
FA [CCK, OFDM]: [0, 39]
CCA spoofing [CCK, OFDM]: [0, 0]
CCK SFD: 0, SIG_GG: 0
OFDM Parity: 4, Rate: 2, LSIG_BRK_S: 0, LSIG_BRK_L: 7, SBD: 5
AMPDU miss: 0
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.h | 87 ++++++++
drivers/net/wireless/realtek/rtw89/debug.c | 33 +++
drivers/net/wireless/realtek/rtw89/phy.c | 195 ++++++++++++++++++
drivers/net/wireless/realtek/rtw89/reg.h | 127 ++++++++++++
drivers/net/wireless/realtek/rtw89/rtw8851b.c | 49 +++++
drivers/net/wireless/realtek/rtw89/rtw8852a.c | 49 +++++
drivers/net/wireless/realtek/rtw89/rtw8852b.c | 49 +++++
.../net/wireless/realtek/rtw89/rtw8852bt.c | 49 +++++
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 49 +++++
drivers/net/wireless/realtek/rtw89/rtw8922a.c | 49 +++++
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 49 +++++
11 files changed, 785 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index c4396f0100be..7f869a339ee6 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -4487,6 +4487,54 @@ struct rtw89_edcca_regs {
u32 tx_collision_t2r_st_mask;
};
+struct rtw89_pmac_regs {
+ struct rtw89_reg_def cck_txon;
+ struct rtw89_reg_def cck_txen;
+ struct rtw89_reg_def cck_cca;
+ struct rtw89_reg_def cck_sfd_gg;
+ struct rtw89_reg_def cck_sig_gg;
+ struct rtw89_reg_def cck_spoofing;
+ struct rtw89_reg_def cck_brk;
+ struct rtw89_reg_def brk;
+ struct rtw89_reg_def brk_option;
+ struct rtw89_reg_def search_fail;
+ struct rtw89_reg_def lsig_brk_s_th;
+ struct rtw89_reg_def lsig_brk_l_th;
+ struct rtw89_reg_def rxl_err_parity;
+ struct rtw89_reg_def rxl_err_rate;
+ struct rtw89_reg_def ofdm_cca;
+ struct rtw89_reg_def cca_spoofing;
+ struct rtw89_reg_def ampdu_miss;
+ struct rtw89_reg_def r1b_rx_rpt_rst;
+ struct rtw89_reg_def r1b_rr_sel;
+ struct rtw89_reg_def enable_all_cnt;
+ struct rtw89_reg_def rst_all_cnt;
+ u32 cck_crc32;
+ u32 cck_crc32_ok_mask;
+ u32 cck_crc32_fail_mask;
+ u32 ofdm_txon;
+ u32 ofdm_txon_mask;
+ u32 ofdm_txen_mask;
+ u32 l_crc;
+ u32 l_crc_ok_mask;
+ u32 l_crc_err_mask;
+ u32 ht_crc;
+ u32 ht_crc_ok_mask;
+ u32 ht_crc_err_mask;
+ u32 vht_crc;
+ u32 vht_crc_ok_mask;
+ u32 vht_crc_err_mask;
+ u32 he_crc;
+ u32 he_crc_ok_mask;
+ u32 he_crc_err_mask;
+ u32 eht_crc;
+ u32 eht_crc_ok_mask;
+ u32 eht_crc_err_mask;
+ u32 ampdu_crc;
+ u32 ampdu_crc_ok_mask;
+ u32 ampdu_crc_err_mask;
+};
+
struct rtw89_phy_ul_tb_info {
bool dyn_tb_tri_en;
u8 def_if_bandedge;
@@ -4682,6 +4730,7 @@ struct rtw89_chip_info {
struct rtw89_sb_regs btc_sb;
u32 dma_ch_mask;
const struct rtw89_edcca_regs *edcca_regs;
+ const struct rtw89_pmac_regs *pmac_regs;
const struct wiphy_wowlan_support *wowlan_stub;
const struct rtw89_xtal_info *xtal_info;
unsigned long default_quirks; /* bitmap of rtw89_quirks */
@@ -5505,6 +5554,43 @@ struct rtw89_phy_ch_info {
u8 is_noisy;
};
+struct rtw89_pmac_stat_info {
+ u32 cck_phy_txon;
+ u32 cck_mac_txen;
+ u32 ofdm_mac_txen;
+ u32 ofdm_phy_txon;
+ u32 cnt_ofdm_cca;
+ u32 cnt_cck_cca;
+ u32 cnt_cck_spoofing;
+ u32 cnt_ofdm_spoofing;
+ u32 cnt_ampdu_miss;
+ u32 cnt_ampdu_crc_error;
+ u32 cnt_ampdu_crc_ok;
+ u32 cnt_cck_crc32_error;
+ u32 cnt_cck_crc32_ok;
+ u32 cnt_ofdm_crc32_error;
+ u32 cnt_ofdm_crc32_ok;
+ u32 cnt_ht_crc32_error;
+ u32 cnt_ht_crc32_ok;
+ u32 cnt_vht_crc32_error;
+ u32 cnt_vht_crc32_ok;
+ u32 cnt_he_crc32_ok;
+ u32 cnt_he_crc32_error;
+ u32 cnt_eht_crc32_ok;
+ u32 cnt_eht_crc32_error;
+ u32 cnt_crc32_error_all;
+ u32 cnt_crc32_ok_all;
+ u32 cnt_sfd_gg;
+ u32 cnt_sig_gg;
+ u32 cnt_cck_fail;
+ u32 cnt_ofdm_fail;
+ u32 cnt_lsig_brk_s_th;
+ u32 cnt_lsig_brk_l_th;
+ u32 cnt_parity_fail;
+ u32 cnt_rate_illegal;
+ u32 cnt_sb_search_fail;
+};
+
struct rtw89_agc_gaincode_set {
u8 lna_idx;
u8 tia_idx;
@@ -6331,6 +6417,7 @@ struct rtw89_dev {
struct ewma_rssi bcn_rssi;
struct rtw89_pkt_stat cur_pkt_stat;
struct rtw89_pkt_stat last_pkt_stat;
+ struct rtw89_pmac_stat_info pmac_stat;
} bbs[RTW89_PHY_NUM];
struct wiphy_delayed_work track_work;
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index b82b13645fb0..d8a183bfc6da 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -4141,10 +4141,43 @@ static ssize_t rtw89_debug_priv_phy_info_get(struct rtw89_dev *rtwdev,
static int rtw89_get_bb_stat(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
char *buf, size_t bufsz)
{
+ struct rtw89_pmac_stat_info *pmac = &bb->pmac_stat;
char *p = buf, *end = buf + bufsz;
p += scnprintf(p, end - p, "\n[PHY %u]\n", bb->phy_idx);
+ p += scnprintf(p, end - p, "== PMAC\n");
+ p += scnprintf(p, end - p,
+ "TX [CCK_TXEN, CCK_TXON, OFDM_TXEN, OFDM_TXON]: [%d, %d, %d, %d]\n",
+ pmac->cck_mac_txen, pmac->cck_phy_txon,
+ pmac->ofdm_mac_txen, pmac->ofdm_phy_txon);
+ p += scnprintf(p, end - p, "CRC [CCK, OFDM, HT, VHT, HE, EHT, ALL, MPDU]\n");
+ p += scnprintf(p, end - p, " ok: [%d, %d, %d, %d, %d, %d, %d, %d]\n",
+ pmac->cnt_cck_crc32_ok, pmac->cnt_ofdm_crc32_ok,
+ pmac->cnt_ht_crc32_ok, pmac->cnt_vht_crc32_ok,
+ pmac->cnt_he_crc32_ok, pmac->cnt_eht_crc32_ok,
+ pmac->cnt_crc32_ok_all, pmac->cnt_ampdu_crc_ok);
+ p += scnprintf(p, end - p, "err: [%d, %d, %d, %d, %d, %d, %d, %d]\n",
+ pmac->cnt_cck_crc32_error, pmac->cnt_ofdm_crc32_error,
+ pmac->cnt_ht_crc32_error, pmac->cnt_vht_crc32_error,
+ pmac->cnt_he_crc32_error, pmac->cnt_eht_crc32_error,
+ pmac->cnt_crc32_error_all, pmac->cnt_ampdu_crc_error);
+ p += scnprintf(p, end - p, "CCA [CCK, OFDM]: [%d, %d]\n",
+ pmac->cnt_cck_cca, pmac->cnt_ofdm_cca);
+ p += scnprintf(p, end - p, "FA [CCK, OFDM]: [%d, %d]\n",
+ pmac->cnt_cck_fail, pmac->cnt_ofdm_fail);
+
+ p += scnprintf(p, end - p, "CCA spoofing [CCK, OFDM]: [%d, %d]\n",
+ pmac->cnt_cck_spoofing, pmac->cnt_ofdm_spoofing);
+ p += scnprintf(p, end - p, "CCK SFD: %d, SIG_GG: %d\n",
+ pmac->cnt_sfd_gg, pmac->cnt_sig_gg);
+ p += scnprintf(p, end - p,
+ "OFDM Parity: %d, Rate: %d, LSIG_BRK_S: %d, LSIG_BRK_L: %d, SBD: %d\n",
+ pmac->cnt_parity_fail, pmac->cnt_rate_illegal,
+ pmac->cnt_lsig_brk_s_th, pmac->cnt_lsig_brk_l_th,
+ pmac->cnt_sb_search_fail);
+ p += scnprintf(p, end - p, "AMPDU miss: %d\n\n", pmac->cnt_ampdu_miss);
+
p += scnprintf(p, end - p, "== RSSI/RX Rate\n");
p += rtw89_get_rx_pkt_stat(rtwdev, bb, p, end - p);
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 3124a99d5381..80d358d80a38 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -5844,6 +5844,196 @@ static void rtw89_phy_stat_init(struct rtw89_dev *rtwdev)
rtwdev->hal.thermal_prot_lv = 0;
}
+static void rtw89_phy_pmac_stat_reset(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, bool cck)
+{
+ const struct rtw89_pmac_regs *regs = rtwdev->chip->pmac_regs;
+
+ if (cck) {
+ rtw89_phy_write32_clr(rtwdev, regs->r1b_rx_rpt_rst.addr,
+ regs->r1b_rx_rpt_rst.mask);
+ rtw89_phy_write32_set(rtwdev, regs->r1b_rx_rpt_rst.addr,
+ regs->r1b_rx_rpt_rst.mask);
+ }
+
+ rtw89_phy_write32_idx_set(rtwdev, regs->enable_all_cnt.addr,
+ regs->enable_all_cnt.mask, bb->phy_idx);
+ rtw89_phy_write32_idx_set(rtwdev, regs->rst_all_cnt.addr,
+ regs->rst_all_cnt.mask, bb->phy_idx);
+ rtw89_phy_write32_idx_clr(rtwdev, regs->rst_all_cnt.addr,
+ regs->rst_all_cnt.mask, bb->phy_idx);
+}
+
+static void rtw89_phy_pmac_stat_cck(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
+{
+ const struct rtw89_pmac_regs *regs = rtwdev->chip->pmac_regs;
+ struct rtw89_pmac_stat_info *pmac = &bb->pmac_stat;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u32 val;
+
+ pmac->cck_phy_txon =
+ rtw89_phy_read32_mask(rtwdev, regs->cck_txon.addr, regs->cck_txon.mask);
+ pmac->cck_mac_txen =
+ rtw89_phy_read32_mask(rtwdev, regs->cck_txen.addr, regs->cck_txen.mask);
+
+ if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev))
+ rtw89_phy_write32_mask(rtwdev, regs->r1b_rr_sel.addr,
+ regs->r1b_rr_sel.mask, 0x2);
+
+ if (bb->phy_idx == RTW89_PHY_1)
+ pmac->cnt_cck_cca =
+ rtw89_phy_read32_mask(rtwdev, regs->cck_cca.addr + 8,
+ regs->cck_cca.mask);
+ else
+ pmac->cnt_cck_cca =
+ rtw89_phy_read32_mask(rtwdev, regs->cck_cca.addr,
+ regs->cck_cca.mask);
+
+ if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev))
+ rtw89_phy_write32_mask(rtwdev, regs->r1b_rr_sel.addr,
+ regs->r1b_rr_sel.mask, 0x1);
+
+ if (bb->phy_idx == RTW89_PHY_1)
+ val = rtw89_phy_read32(rtwdev, regs->cck_crc32 + 8);
+ else
+ val = rtw89_phy_read32(rtwdev, regs->cck_crc32);
+ pmac->cnt_cck_crc32_ok = field_get(regs->cck_crc32_ok_mask, val);
+ pmac->cnt_cck_crc32_error = field_get(regs->cck_crc32_fail_mask, val);
+
+ pmac->cnt_sfd_gg =
+ rtw89_phy_read32_idx(rtwdev, regs->cck_sfd_gg.addr,
+ regs->cck_sfd_gg.mask, bb->phy_idx);
+ pmac->cnt_sig_gg =
+ rtw89_phy_read32_idx(rtwdev, regs->cck_sig_gg.addr,
+ regs->cck_sig_gg.mask, bb->phy_idx);
+ pmac->cnt_cck_spoofing =
+ rtw89_phy_read32_idx(rtwdev, regs->cck_spoofing.addr,
+ regs->cck_spoofing.mask, bb->phy_idx);
+
+ if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev))
+ pmac->cnt_cck_fail =
+ pmac->cnt_cck_cca - pmac->cnt_cck_crc32_ok -
+ pmac->cnt_cck_crc32_error - pmac->cnt_cck_spoofing;
+ else
+ pmac->cnt_cck_fail =
+ rtw89_phy_read32_idx(rtwdev, regs->cck_brk.addr,
+ regs->cck_brk.mask, bb->phy_idx);
+}
+
+static void rtw89_phy_pmac_stat_ofdm(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
+{
+ const struct rtw89_pmac_regs *regs = rtwdev->chip->pmac_regs;
+ struct rtw89_pmac_stat_info *pmac = &bb->pmac_stat;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u32 val;
+
+ val = rtw89_phy_read32_idx(rtwdev, regs->ofdm_txon, MASKDWORD, bb->phy_idx);
+ pmac->ofdm_phy_txon = field_get(regs->ofdm_txon_mask, val);
+ pmac->ofdm_mac_txen = field_get(regs->ofdm_txen_mask, val);
+
+ val = rtw89_phy_read32_idx(rtwdev, regs->l_crc, MASKDWORD, bb->phy_idx);
+ pmac->cnt_ofdm_crc32_ok = field_get(regs->l_crc_ok_mask, val);
+ pmac->cnt_ofdm_crc32_error = field_get(regs->l_crc_err_mask, val);
+
+ val = rtw89_phy_read32_idx(rtwdev, regs->ht_crc, MASKDWORD, bb->phy_idx);
+ pmac->cnt_ht_crc32_ok = field_get(regs->ht_crc_ok_mask, val);
+ pmac->cnt_ht_crc32_error = field_get(regs->ht_crc_err_mask, val);
+
+ val = rtw89_phy_read32_idx(rtwdev, regs->vht_crc, MASKDWORD, bb->phy_idx);
+ pmac->cnt_vht_crc32_ok = field_get(regs->vht_crc_ok_mask, val);
+ pmac->cnt_vht_crc32_error = field_get(regs->vht_crc_err_mask, val);
+
+ val = rtw89_phy_read32_idx(rtwdev, regs->he_crc, MASKDWORD, bb->phy_idx);
+ pmac->cnt_he_crc32_ok = field_get(regs->he_crc_ok_mask, val);
+ pmac->cnt_he_crc32_error = field_get(regs->he_crc_err_mask, val);
+
+ if (chip->chip_gen == RTW89_CHIP_BE) {
+ val = rtw89_phy_read32_idx(rtwdev, regs->eht_crc,
+ MASKDWORD, bb->phy_idx);
+ pmac->cnt_eht_crc32_ok = field_get(regs->eht_crc_ok_mask, val);
+ pmac->cnt_eht_crc32_error = field_get(regs->eht_crc_err_mask, val);
+ }
+
+ val = rtw89_phy_read32_idx(rtwdev, regs->ampdu_crc, MASKDWORD, bb->phy_idx);
+ pmac->cnt_ampdu_crc_ok = field_get(regs->ampdu_crc_ok_mask, val);
+ pmac->cnt_ampdu_crc_error = field_get(regs->ampdu_crc_err_mask, val);
+
+ val = rtw89_phy_read32_idx(rtwdev, regs->brk.addr, regs->brk.mask, bb->phy_idx);
+ if (chip->chip_id == RTL8852C &&
+ rtw89_phy_read32_idx(rtwdev, regs->brk_option.addr,
+ regs->brk_option.mask, bb->phy_idx) == 1) {
+ u32 tmp = pmac->ofdm_phy_txon + pmac->cck_phy_txon;
+
+ val = (val > tmp) ? (val - tmp) : 0;
+ }
+ pmac->cnt_ofdm_fail = val;
+
+ pmac->cnt_sb_search_fail =
+ rtw89_phy_read32_idx(rtwdev, regs->search_fail.addr,
+ regs->search_fail.mask, bb->phy_idx);
+ pmac->cnt_lsig_brk_s_th =
+ rtw89_phy_read32_idx(rtwdev, regs->lsig_brk_s_th.addr,
+ regs->lsig_brk_s_th.mask, bb->phy_idx);
+ pmac->cnt_lsig_brk_l_th =
+ rtw89_phy_read32_idx(rtwdev, regs->lsig_brk_l_th.addr,
+ regs->lsig_brk_l_th.mask, bb->phy_idx);
+ pmac->cnt_parity_fail =
+ rtw89_phy_read32_idx(rtwdev, regs->rxl_err_parity.addr,
+ regs->rxl_err_parity.mask, bb->phy_idx);
+ pmac->cnt_rate_illegal =
+ rtw89_phy_read32_idx(rtwdev, regs->rxl_err_rate.addr,
+ regs->rxl_err_rate.mask, bb->phy_idx);
+ pmac->cnt_ofdm_cca =
+ rtw89_phy_read32_idx(rtwdev, regs->ofdm_cca.addr,
+ regs->ofdm_cca.mask, bb->phy_idx);
+ pmac->cnt_ofdm_spoofing =
+ rtw89_phy_read32_idx(rtwdev, regs->cca_spoofing.addr,
+ regs->cca_spoofing.mask, bb->phy_idx);
+ pmac->cnt_ampdu_miss =
+ rtw89_phy_read32_idx(rtwdev, regs->ampdu_miss.addr,
+ regs->ampdu_miss.mask, bb->phy_idx);
+}
+
+static void rtw89_phy_pmac_stat_update(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
+{
+ struct rtw89_pmac_stat_info *pmac = &bb->pmac_stat;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_entity_conf conf;
+ const struct rtw89_chan *chan;
+ bool cck;
+
+ rtw89_entity_get_conf(rtwdev, &conf);
+ chan = conf.chans[bb->phy_idx];
+ cck = chan->band_type == RTW89_BAND_2G;
+
+ if (cck)
+ rtw89_phy_pmac_stat_cck(rtwdev, bb);
+
+ rtw89_phy_pmac_stat_ofdm(rtwdev, bb);
+
+ pmac->cnt_crc32_error_all = pmac->cnt_he_crc32_error +
+ pmac->cnt_vht_crc32_error +
+ pmac->cnt_ht_crc32_error +
+ pmac->cnt_ofdm_crc32_error +
+ pmac->cnt_cck_crc32_error;
+
+ pmac->cnt_crc32_ok_all = pmac->cnt_he_crc32_ok +
+ pmac->cnt_vht_crc32_ok +
+ pmac->cnt_ht_crc32_ok +
+ pmac->cnt_ofdm_crc32_ok +
+ pmac->cnt_cck_crc32_ok;
+
+ if (chip->chip_gen == RTW89_CHIP_BE) {
+ pmac->cnt_crc32_error_all += pmac->cnt_eht_crc32_error;
+ pmac->cnt_crc32_ok_all += pmac->cnt_eht_crc32_ok;
+ }
+
+ rtw89_phy_pmac_stat_reset(rtwdev, bb, cck);
+}
+
static void rtw89_phy_trigger_tx_count(struct rtw89_dev *rtwdev)
{
if (RTW89_CHK_FW_FEATURE(TX_HISTORY_V1, &rtwdev->fw))
@@ -5854,10 +6044,15 @@ static void rtw89_phy_trigger_tx_count(struct rtw89_dev *rtwdev)
static void rtw89_phy_stat_update(struct rtw89_dev *rtwdev)
{
+ struct rtw89_bb_ctx *bb;
+
if (!rtwdev->phy_info.bb_stat_cfg.enable)
return;
rtw89_phy_trigger_tx_count(rtwdev);
+
+ rtw89_for_each_active_bb(rtwdev, bb)
+ rtw89_phy_pmac_stat_update(rtwdev, bb);
}
void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 1e1125235f0c..c054a402bd20 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -8799,6 +8799,12 @@
#define R_P0_ANT_SW 0x0728
#define B_P0_HW_ANTSW_DIS_BY_GNT_BT BIT(12)
#define B_P0_TRSW_TX_EXTEND GENMASK(3, 0)
+#define R_RST_ALL_CNT 0x0730
+#define R_RST_ALL_CNT_BE4 0x20730
+#define B_RST_ALL_CNT BIT(0)
+#define R_ENABLE_ALL_CNT 0x0730
+#define R_ENABLE_ALL_CNT_BE4 0x20730
+#define B_ENABLE_ALL_CNT BIT(1)
#define R_MAC_PIN_SEL 0x0734
#define R_MAC_PIN_SEL_BE4 0x20734
#define B_CH_IDX_SEG0 GENMASK(23, 16)
@@ -8949,6 +8955,8 @@
#define B_RXHT_MCS_LIMIT GENMASK(9, 8)
#define R_RXVHT_MCS_LIMIT 0x0D18
#define B_RXVHT_MCS_LIMIT GENMASK(22, 21)
+#define R_BRK_OPT 0x0D44
+#define B_BRK_OPT BIT(31)
#define R_P0_EN_SOUND_WO_NDP 0x0D7C
#define B_P0_EN_SOUND_WO_NDP BIT(1)
#define R_RXHE 0x0D80
@@ -9004,6 +9012,21 @@
#define R_CFO_COMP_SEG0_L 0x1384
#define R_CFO_COMP_SEG0_H 0x1388
#define R_CFO_COMP_SEG0_CTRL 0x138C
+#define R_CNT_CCKTXEN 0x1700
+#define R_CNT_CCKTXEN_V1 0x2E00
+#define R_CNT_CCKTXEN_BE4 0x2CF00
+#define B_CNT_CCKTXEN GENMASK(31, 16)
+#define R_CNT_CCKTXON 0x1704
+#define R_CNT_CCKTXON_V1 0x2E04
+#define R_CNT_CCKTXON_BE4 0x2CF04
+#define B_CNT_CCKTXON GENMASK(15, 0)
+#define R_CNT_CCK_CCA_P0 0x1710
+#define R_CNT_CCK_CCA_P0_V1 0x2E10
+#define B_CNT_CCK_CCA_P0 GENMASK(15, 0)
+#define R_CNT_CCK_CRC32_P0 0x1714
+#define R_CNT_CCK_CRC32_P0_V1 0x2E14
+#define B_CNT_CCK_CRC32OK_P0 GENMASK(15, 0)
+#define B_CNT_CCK_CRC32FAIL_P0 GENMASK(31, 16)
#define R_DBG32_D 0x1730
#define R_EDCCA_RPT_A 0x1738
#define R_EDCCA_RPT_B 0x173c
@@ -9019,7 +9042,73 @@
#define B_SWSI_W_BUSY_V1 BIT(24)
#define B_SWSI_R_BUSY_V1 BIT(25)
#define B_SWSI_R_DATA_DONE_V1 BIT(26)
+#define R_CNT_LSIG_BRK_S_TH 0x1A00
+#define R_CNT_LSIG_BRK_S_TH_V1 0x0E00
+#define R_CNT_LSIG_BRK_S_TH_BE4 0x20E00
+#define B_CNT_LSIG_BRK_S_TH GENMASK(31, 16)
+#define R_CNT_CCA_SPOOFING 0x1A00
+#define R_CNT_CCA_SPOOFING_V1 0x0E00
+#define R_CNT_CCA_SPOOFING_BE4 0x20E00
+#define B_CNT_CCA_SPOOFING GENMASK(15, 0)
+#define R_CNT_LSIG_BRK_L_TH 0x1A04
+#define R_CNT_LSIG_BRK_L_TH_V1 0x0E04
+#define R_CNT_LSIG_BRK_L_TH_BE4 0x20E04
+#define B_CNT_LSIG_BRK_L_TH GENMASK(15, 0)
+#define R_CNT_BRK 0x1A08
+#define R_CNT_BRK_V1 0x0E08
+#define R_CNT_BRK_BE4 0x20E08
+#define B_CNT_BRK GENMASK(31, 16)
+#define R_CNT_RXL_ERR_PARITY 0x1A0C
+#define R_CNT_RXL_ERR_PARITY_V1 0x0E0C
+#define R_CNT_RXL_ERR_PARITY_BE4 0x20E0C
+#define B_CNT_RXL_ERR_PARITY GENMASK(31, 16)
+#define R_CNT_RXL_ERR_RATE 0x1A10
+#define R_CNT_RXL_ERR_RATE_V1 0x0E10
+#define R_CNT_RXL_ERR_RATE_BE4 0x20E10
+#define B_CNT_RXL_ERR_RATE GENMASK(15, 0)
+#define R_CNT_SEARCH_FAIL 0x1A20
+#define R_CNT_SEARCH_FAIL_V1 0x0E20
+#define R_CNT_SEARCH_FAIL_BE4 0x20E20
+#define B_CNT_SEARCH_FAIL GENMASK(31, 16)
+#define R_CNT_OFDM_CCA 0x1A24
+#define R_CNT_OFDM_CCA_V1 0x0E24
+#define R_CNT_OFDM_CCA_BE4 0x20E24
+#define B_CNT_OFDM_CCA GENMASK(15, 0)
#define R_TX_COUNTER 0x1A40
+#define R_CNT_OFDMTXON 0x1A40
+#define R_CNT_OFDMTXON_V1 0x0E40
+#define R_CNT_OFDMTXON_BE4 0x20E40
+#define B_CNT_OFDMTXON GENMASK(15, 0)
+#define B_CNT_OFDMTXEN GENMASK(31, 16)
+#define R_CNT_HE_CRC 0x1A58
+#define R_CNT_HE_CRC_V1 0x0E58
+#define R_CNT_HE_CRC_BE4 0x20E58
+#define B_CNT_HE_CRC_OK GENMASK(15, 0)
+#define B_CNT_HE_CRC_ERR GENMASK(31, 16)
+#define R_CNT_VHT_CRC 0x1A5C
+#define R_CNT_VHT_CRC_V1 0x0E5C
+#define R_CNT_VHT_CRC_BE4 0x20E5C
+#define B_CNT_VHT_CRC_OK GENMASK(15, 0)
+#define B_CNT_VHT_CRC_ERR GENMASK(31, 16)
+#define R_CNT_HT_CRC 0x1A60
+#define R_CNT_HT_CRC_V1 0x0E60
+#define R_CNT_HT_CRC_BE4 0x20E60
+#define B_CNT_HT_CRC_OK GENMASK(15, 0)
+#define B_CNT_HT_CRC_ERR GENMASK(31, 16)
+#define R_CNT_L_CRC 0x1A64
+#define R_CNT_L_CRC_V1 0x0E64
+#define R_CNT_L_CRC_BE4 0x20E64
+#define B_CNT_L_CRC_OK GENMASK(15, 0)
+#define B_CNT_L_CRC_ERR GENMASK(31, 16)
+#define R_CNT_AMPDU_MISS 0x1A7C
+#define R_CNT_AMPDU_MISS_V1 0x0E7C
+#define R_CNT_AMPDU_MISS_BE4 0x20E7C
+#define B_CNT_AMPDU_MISS GENMASK(31, 16)
+#define R_CNT_AMPDU_RX_CRC32 0x1A80
+#define R_CNT_AMPDU_RX_CRC32_V1 0x0E80
+#define R_CNT_AMPDU_RX_CRC32_BE4 0x20E80
+#define B_CNT_AMPDU_RX_CRC32_OK GENMASK(15, 0)
+#define B_CNT_AMPDU_RX_CRC32_ERR GENMASK(31, 16)
#define R_NHM_CNT0 0x1A88
#define B_NHM_CNT0_MSK GENMASK(15, 0)
#define B_NHM_CNT1_MSK GENMASK(31, 16)
@@ -9137,12 +9226,41 @@
#define B_RXCCA_DIS_V1 BIT(0)
#define R_RXSC 0x237C
#define B_RXSC_EN BIT(0)
+#define R_R1B_RR_SEL 0x2388
+#define B_R1B_RR_SEL GENMASK(24, 23)
+#define R_R1B_RX_RPT_RST 0x2388
+#define R_R1B_RX_RPT_RST_V1 0x2340
+#define R_R1B_RX_RPT_RST_BE 0x0540
+#define R_R1B_RX_RPT_RST_BE4 0x20540
+#define B_R1B_RX_RPT_RST BIT(15)
+#define B_R1B_RX_RPT_RST_V1 BIT(7)
+#define R_BRK_CNT 0x239C
+#define R_BRK_CNT_V1 0x059C
+#define R_BRK_CNT_BE4 0x2059C
+#define B_BRK_CNT GENMASK(31, 16)
#define R_RX_RPL_OFST 0x23AC
#define B_RX_RPL_OFST_CCK_MASK GENMASK(6, 0)
#define R_RXSCOBC 0x23B0
#define B_RXSCOBC_TH GENMASK(18, 0)
#define R_RXSCOCCK 0x23B4
#define B_RXSCOCCK_TH GENMASK(18, 0)
+#define R_SFD_GG_CNT 0x23E0
+#define R_SFD_GG_CNT_V1 0x23A0
+#define R_SFD_GG_CNT_V2 0x05A0
+#define R_SFD_GG_CNT_BE4 0x205A0
+#define B_SFD_GG_CNT GENMASK(15, 0)
+#define R_SIG_GG_CNT 0x23E8
+#define R_SIG_GG_CNT_V1 0x23AC
+#define R_SIG_GG_CNT_V2 0x05AC
+#define R_SIG_GG_CNT_BE4 0x205AC
+#define B_SIG_GG_CNT GENMASK(15, 0)
+#define B_SIG_GG_CNT_V1 GENMASK(15, 8)
+#define R_SPOOF_CNT 0x23EC
+#define R_SPOOF_CNT_V1 0x23A8
+#define R_SPOOF_CNT_V2 0x05A8
+#define R_SPOOF_CNT_BE4 0x205A8
+#define B_SPOOF_CNT GENMASK(7, 0)
+#define B_SPOOF_CNT_V1 GENMASK(31, 16)
#define R_P80_AT_HIGH_FREQ_RU_ALLOC 0x2410
#define B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY1 BIT(14)
#define B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY0 BIT(13)
@@ -9179,6 +9297,10 @@
#define R_EDCCA_RPT_B_BE4_C1 0x2FE34
#define R_EDCCA_RPT_P1_A_BE 0x2E40
#define R_EDCCA_RPT_P1_B_BE 0x2E44
+#define R_CNT_EHT_CRC 0x2F00
+#define R_CNT_EHT_CRC_BE4 0x22F00
+#define B_CNT_EHT_CRC_OK GENMASK(15, 0)
+#define B_CNT_EHT_CRC_ERR GENMASK(31, 16)
#define R_S1_HW_SI_DIS 0x3200
#define B_S1_HW_SI_DIS_W_R_TRIG GENMASK(30, 28)
#define R_P1_RXCK 0x32A0
@@ -10547,6 +10669,11 @@
#define R_IFS_T3_HIS_BE4 0x20F54
#define B_IFS_T3_HIS_BE4 GENMASK(15, 0)
#define B_IFS_T4_HIS_BE4 GENMASK(31, 16)
+#define R_CNT_CCK_CCA_BE4 0x20FE8
+#define B_CNT_CCK_CCA_BE4 GENMASK(15, 0)
+#define R_CNT_CCK_CRC32_BE4 0x20FEC
+#define B_CNT_CCK_CRC32OK_BE4 GENMASK(15, 0)
+#define B_CNT_CCK_CRC32FAIL_BE4 GENMASK(31, 16)
#define R_TX_ERROR_SEL_BE4 0x21254
#define B_TX_ERROR_PSDU_BE4 BIT(11)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index d9a144b4bf58..e047e716d9e3 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -307,6 +307,54 @@ static const struct rtw89_edcca_regs rtw8851b_edcca_regs = {
.tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M,
};
+static const struct rtw89_pmac_regs rtw8851b_pmac_regs = {
+ .cck_txon = {R_CNT_CCKTXON, B_CNT_CCKTXON},
+ .cck_txen = {R_CNT_CCKTXEN, B_CNT_CCKTXEN},
+ .cck_cca = {R_CNT_CCK_CCA_P0, B_CNT_CCK_CCA_P0},
+ .cck_sfd_gg = {R_SFD_GG_CNT, B_SFD_GG_CNT},
+ .cck_sig_gg = {R_SIG_GG_CNT, B_SIG_GG_CNT},
+ .cck_spoofing = {R_SPOOF_CNT, B_SPOOF_CNT},
+ .cck_brk = {},
+ .brk = {R_CNT_BRK, B_CNT_BRK},
+ .brk_option = {},
+ .search_fail = {R_CNT_SEARCH_FAIL, B_CNT_SEARCH_FAIL},
+ .lsig_brk_s_th = {R_CNT_LSIG_BRK_S_TH, B_CNT_LSIG_BRK_S_TH},
+ .lsig_brk_l_th = {R_CNT_LSIG_BRK_L_TH, B_CNT_LSIG_BRK_L_TH},
+ .rxl_err_parity = {R_CNT_RXL_ERR_PARITY, B_CNT_RXL_ERR_PARITY},
+ .rxl_err_rate = {R_CNT_RXL_ERR_RATE, B_CNT_RXL_ERR_RATE},
+ .ofdm_cca = {R_CNT_OFDM_CCA, B_CNT_OFDM_CCA},
+ .cca_spoofing = {R_CNT_CCA_SPOOFING, B_CNT_CCA_SPOOFING},
+ .ampdu_miss = {R_CNT_AMPDU_MISS, B_CNT_AMPDU_MISS},
+ .r1b_rx_rpt_rst = {R_R1B_RX_RPT_RST, B_R1B_RX_RPT_RST},
+ .r1b_rr_sel = {R_R1B_RR_SEL, B_R1B_RR_SEL},
+ .enable_all_cnt = {R_ENABLE_ALL_CNT, B_ENABLE_ALL_CNT},
+ .rst_all_cnt = {R_RST_ALL_CNT, B_RST_ALL_CNT},
+ .cck_crc32 = R_CNT_CCK_CRC32_P0,
+ .cck_crc32_ok_mask = B_CNT_CCK_CRC32OK_P0,
+ .cck_crc32_fail_mask = B_CNT_CCK_CRC32FAIL_P0,
+ .ofdm_txon = R_CNT_OFDMTXON,
+ .ofdm_txon_mask = B_CNT_OFDMTXON,
+ .ofdm_txen_mask = B_CNT_OFDMTXEN,
+ .l_crc = R_CNT_L_CRC,
+ .l_crc_ok_mask = B_CNT_L_CRC_OK,
+ .l_crc_err_mask = B_CNT_L_CRC_ERR,
+ .ht_crc = R_CNT_HT_CRC,
+ .ht_crc_ok_mask = B_CNT_HT_CRC_OK,
+ .ht_crc_err_mask = B_CNT_HT_CRC_ERR,
+ .vht_crc = R_CNT_VHT_CRC,
+ .vht_crc_ok_mask = B_CNT_VHT_CRC_OK,
+ .vht_crc_err_mask = B_CNT_VHT_CRC_ERR,
+ .he_crc = R_CNT_HE_CRC,
+ .he_crc_ok_mask = B_CNT_HE_CRC_OK,
+ .he_crc_err_mask = B_CNT_HE_CRC_ERR,
+ .eht_crc = 0,
+ .eht_crc_ok_mask = 0,
+ .eht_crc_err_mask = 0,
+ .ampdu_crc = R_CNT_AMPDU_RX_CRC32,
+ .ampdu_crc_ok_mask = B_CNT_AMPDU_RX_CRC32_OK,
+ .ampdu_crc_err_mask = B_CNT_AMPDU_RX_CRC32_ERR,
+};
+
static const struct rtw89_btc_rf_trx_para rtw89_btc_8851b_rf_ul[] = {
{255, 0, 0, 7}, /* 0 -> original */
{255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */
@@ -2722,6 +2770,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) |
BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI),
.edcca_regs = &rtw8851b_edcca_regs,
+ .pmac_regs = &rtw8851b_pmac_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8851b,
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index b81eeb59be60..686e489d42f2 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -621,6 +621,54 @@ static const struct rtw89_edcca_regs rtw8852a_edcca_regs = {
.tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M,
};
+static const struct rtw89_pmac_regs rtw8852a_pmac_regs = {
+ .cck_txon = {R_CNT_CCKTXON, B_CNT_CCKTXON},
+ .cck_txen = {R_CNT_CCKTXEN, B_CNT_CCKTXEN},
+ .cck_cca = {R_CNT_CCK_CCA_P0, B_CNT_CCK_CCA_P0},
+ .cck_sfd_gg = {R_SFD_GG_CNT, B_SFD_GG_CNT},
+ .cck_sig_gg = {R_SIG_GG_CNT, B_SIG_GG_CNT},
+ .cck_spoofing = {R_SPOOF_CNT, B_SPOOF_CNT},
+ .cck_brk = {},
+ .brk = {R_CNT_BRK, B_CNT_BRK},
+ .brk_option = {},
+ .search_fail = {R_CNT_SEARCH_FAIL, B_CNT_SEARCH_FAIL},
+ .lsig_brk_s_th = {R_CNT_LSIG_BRK_S_TH, B_CNT_LSIG_BRK_S_TH},
+ .lsig_brk_l_th = {R_CNT_LSIG_BRK_L_TH, B_CNT_LSIG_BRK_L_TH},
+ .rxl_err_parity = {R_CNT_RXL_ERR_PARITY, B_CNT_RXL_ERR_PARITY},
+ .rxl_err_rate = {R_CNT_RXL_ERR_RATE, B_CNT_RXL_ERR_RATE},
+ .ofdm_cca = {R_CNT_OFDM_CCA, B_CNT_OFDM_CCA},
+ .cca_spoofing = {R_CNT_CCA_SPOOFING, B_CNT_CCA_SPOOFING},
+ .ampdu_miss = {R_CNT_AMPDU_MISS, B_CNT_AMPDU_MISS},
+ .r1b_rx_rpt_rst = {R_R1B_RX_RPT_RST, B_R1B_RX_RPT_RST},
+ .r1b_rr_sel = {R_R1B_RR_SEL, B_R1B_RR_SEL},
+ .enable_all_cnt = {R_ENABLE_ALL_CNT, B_ENABLE_ALL_CNT},
+ .rst_all_cnt = {R_RST_ALL_CNT, B_RST_ALL_CNT},
+ .cck_crc32 = R_CNT_CCK_CRC32_P0,
+ .cck_crc32_ok_mask = B_CNT_CCK_CRC32OK_P0,
+ .cck_crc32_fail_mask = B_CNT_CCK_CRC32FAIL_P0,
+ .ofdm_txon = R_CNT_OFDMTXON,
+ .ofdm_txon_mask = B_CNT_OFDMTXON,
+ .ofdm_txen_mask = B_CNT_OFDMTXEN,
+ .l_crc = R_CNT_L_CRC,
+ .l_crc_ok_mask = B_CNT_L_CRC_OK,
+ .l_crc_err_mask = B_CNT_L_CRC_ERR,
+ .ht_crc = R_CNT_HT_CRC,
+ .ht_crc_ok_mask = B_CNT_HT_CRC_OK,
+ .ht_crc_err_mask = B_CNT_HT_CRC_ERR,
+ .vht_crc = R_CNT_VHT_CRC,
+ .vht_crc_ok_mask = B_CNT_VHT_CRC_OK,
+ .vht_crc_err_mask = B_CNT_VHT_CRC_ERR,
+ .he_crc = R_CNT_HE_CRC,
+ .he_crc_ok_mask = B_CNT_HE_CRC_OK,
+ .he_crc_err_mask = B_CNT_HE_CRC_ERR,
+ .eht_crc = 0,
+ .eht_crc_ok_mask = 0,
+ .eht_crc_err_mask = 0,
+ .ampdu_crc = R_CNT_AMPDU_RX_CRC32,
+ .ampdu_crc_ok_mask = B_CNT_AMPDU_RX_CRC32_OK,
+ .ampdu_crc_err_mask = B_CNT_AMPDU_RX_CRC32_ERR,
+};
+
static void rtw8852a_efuse_parsing_tssi(struct rtw89_dev *rtwdev,
struct rtw8852a_efuse *map)
{
@@ -2459,6 +2507,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}},
.dma_ch_mask = 0,
.edcca_regs = &rtw8852a_edcca_regs,
+ .pmac_regs = &rtw8852a_pmac_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8852a,
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
index 13c942127225..6ab99f72fda7 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
@@ -259,6 +259,54 @@ static const struct rtw89_edcca_regs rtw8852b_edcca_regs = {
.tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M,
};
+static const struct rtw89_pmac_regs rtw8852b_pmac_regs = {
+ .cck_txon = {R_CNT_CCKTXON, B_CNT_CCKTXON},
+ .cck_txen = {R_CNT_CCKTXEN, B_CNT_CCKTXEN},
+ .cck_cca = {R_CNT_CCK_CCA_P0, B_CNT_CCK_CCA_P0},
+ .cck_sfd_gg = {R_SFD_GG_CNT, B_SFD_GG_CNT},
+ .cck_sig_gg = {R_SIG_GG_CNT, B_SIG_GG_CNT},
+ .cck_spoofing = {R_SPOOF_CNT, B_SPOOF_CNT},
+ .cck_brk = {},
+ .brk = {R_CNT_BRK, B_CNT_BRK},
+ .brk_option = {},
+ .search_fail = {R_CNT_SEARCH_FAIL, B_CNT_SEARCH_FAIL},
+ .lsig_brk_s_th = {R_CNT_LSIG_BRK_S_TH, B_CNT_LSIG_BRK_S_TH},
+ .lsig_brk_l_th = {R_CNT_LSIG_BRK_L_TH, B_CNT_LSIG_BRK_L_TH},
+ .rxl_err_parity = {R_CNT_RXL_ERR_PARITY, B_CNT_RXL_ERR_PARITY},
+ .rxl_err_rate = {R_CNT_RXL_ERR_RATE, B_CNT_RXL_ERR_RATE},
+ .ofdm_cca = {R_CNT_OFDM_CCA, B_CNT_OFDM_CCA},
+ .cca_spoofing = {R_CNT_CCA_SPOOFING, B_CNT_CCA_SPOOFING},
+ .ampdu_miss = {R_CNT_AMPDU_MISS, B_CNT_AMPDU_MISS},
+ .r1b_rx_rpt_rst = {R_R1B_RX_RPT_RST, B_R1B_RX_RPT_RST},
+ .r1b_rr_sel = {R_R1B_RR_SEL, B_R1B_RR_SEL},
+ .enable_all_cnt = {R_ENABLE_ALL_CNT, B_ENABLE_ALL_CNT},
+ .rst_all_cnt = {R_RST_ALL_CNT, B_RST_ALL_CNT},
+ .cck_crc32 = R_CNT_CCK_CRC32_P0,
+ .cck_crc32_ok_mask = B_CNT_CCK_CRC32OK_P0,
+ .cck_crc32_fail_mask = B_CNT_CCK_CRC32FAIL_P0,
+ .ofdm_txon = R_CNT_OFDMTXON,
+ .ofdm_txon_mask = B_CNT_OFDMTXON,
+ .ofdm_txen_mask = B_CNT_OFDMTXEN,
+ .l_crc = R_CNT_L_CRC,
+ .l_crc_ok_mask = B_CNT_L_CRC_OK,
+ .l_crc_err_mask = B_CNT_L_CRC_ERR,
+ .ht_crc = R_CNT_HT_CRC,
+ .ht_crc_ok_mask = B_CNT_HT_CRC_OK,
+ .ht_crc_err_mask = B_CNT_HT_CRC_ERR,
+ .vht_crc = R_CNT_VHT_CRC,
+ .vht_crc_ok_mask = B_CNT_VHT_CRC_OK,
+ .vht_crc_err_mask = B_CNT_VHT_CRC_ERR,
+ .he_crc = R_CNT_HE_CRC,
+ .he_crc_ok_mask = B_CNT_HE_CRC_OK,
+ .he_crc_err_mask = B_CNT_HE_CRC_ERR,
+ .eht_crc = 0,
+ .eht_crc_ok_mask = 0,
+ .eht_crc_err_mask = 0,
+ .ampdu_crc = R_CNT_AMPDU_RX_CRC32,
+ .ampdu_crc_ok_mask = B_CNT_AMPDU_RX_CRC32_OK,
+ .ampdu_crc_err_mask = B_CNT_AMPDU_RX_CRC32_ERR,
+};
+
static const struct rtw89_btc_rf_trx_para rtw89_btc_8852b_rf_ul[] = {
{255, 0, 0, 7}, /* 0 -> original */
{255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */
@@ -1056,6 +1104,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) |
BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI),
.edcca_regs = &rtw8852b_edcca_regs,
+ .pmac_regs = &rtw8852b_pmac_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8852b,
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
index 3fd5990a8bc4..83de26273100 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
@@ -202,6 +202,54 @@ static const struct rtw89_edcca_regs rtw8852bt_edcca_regs = {
.tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M,
};
+static const struct rtw89_pmac_regs rtw8852bt_pmac_regs = {
+ .cck_txon = {R_CNT_CCKTXON, B_CNT_CCKTXON},
+ .cck_txen = {R_CNT_CCKTXEN, B_CNT_CCKTXEN},
+ .cck_cca = {R_CNT_CCK_CCA_P0, B_CNT_CCK_CCA_P0},
+ .cck_sfd_gg = {R_SFD_GG_CNT, B_SFD_GG_CNT},
+ .cck_sig_gg = {R_SIG_GG_CNT, B_SIG_GG_CNT},
+ .cck_spoofing = {R_SPOOF_CNT, B_SPOOF_CNT},
+ .cck_brk = {},
+ .brk = {R_CNT_BRK, B_CNT_BRK},
+ .brk_option = {},
+ .search_fail = {R_CNT_SEARCH_FAIL, B_CNT_SEARCH_FAIL},
+ .lsig_brk_s_th = {R_CNT_LSIG_BRK_S_TH, B_CNT_LSIG_BRK_S_TH},
+ .lsig_brk_l_th = {R_CNT_LSIG_BRK_L_TH, B_CNT_LSIG_BRK_L_TH},
+ .rxl_err_parity = {R_CNT_RXL_ERR_PARITY, B_CNT_RXL_ERR_PARITY},
+ .rxl_err_rate = {R_CNT_RXL_ERR_RATE, B_CNT_RXL_ERR_RATE},
+ .ofdm_cca = {R_CNT_OFDM_CCA, B_CNT_OFDM_CCA},
+ .cca_spoofing = {R_CNT_CCA_SPOOFING, B_CNT_CCA_SPOOFING},
+ .ampdu_miss = {R_CNT_AMPDU_MISS, B_CNT_AMPDU_MISS},
+ .r1b_rx_rpt_rst = {R_R1B_RX_RPT_RST, B_R1B_RX_RPT_RST},
+ .r1b_rr_sel = {R_R1B_RR_SEL, B_R1B_RR_SEL},
+ .enable_all_cnt = {R_ENABLE_ALL_CNT, B_ENABLE_ALL_CNT},
+ .rst_all_cnt = {R_RST_ALL_CNT, B_RST_ALL_CNT},
+ .cck_crc32 = R_CNT_CCK_CRC32_P0,
+ .cck_crc32_ok_mask = B_CNT_CCK_CRC32OK_P0,
+ .cck_crc32_fail_mask = B_CNT_CCK_CRC32FAIL_P0,
+ .ofdm_txon = R_CNT_OFDMTXON,
+ .ofdm_txon_mask = B_CNT_OFDMTXON,
+ .ofdm_txen_mask = B_CNT_OFDMTXEN,
+ .l_crc = R_CNT_L_CRC,
+ .l_crc_ok_mask = B_CNT_L_CRC_OK,
+ .l_crc_err_mask = B_CNT_L_CRC_ERR,
+ .ht_crc = R_CNT_HT_CRC,
+ .ht_crc_ok_mask = B_CNT_HT_CRC_OK,
+ .ht_crc_err_mask = B_CNT_HT_CRC_ERR,
+ .vht_crc = R_CNT_VHT_CRC,
+ .vht_crc_ok_mask = B_CNT_VHT_CRC_OK,
+ .vht_crc_err_mask = B_CNT_VHT_CRC_ERR,
+ .he_crc = R_CNT_HE_CRC,
+ .he_crc_ok_mask = B_CNT_HE_CRC_OK,
+ .he_crc_err_mask = B_CNT_HE_CRC_ERR,
+ .eht_crc = 0,
+ .eht_crc_ok_mask = 0,
+ .eht_crc_err_mask = 0,
+ .ampdu_crc = R_CNT_AMPDU_RX_CRC32,
+ .ampdu_crc_ok_mask = B_CNT_AMPDU_RX_CRC32_OK,
+ .ampdu_crc_err_mask = B_CNT_AMPDU_RX_CRC32_ERR,
+};
+
static const struct rtw89_btc_rf_trx_para rtw89_btc_8852bt_rf_ul[] = {
{255, 0, 0, 7}, /* 0 -> original */
{255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */
@@ -893,6 +941,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) |
BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI),
.edcca_regs = &rtw8852bt_edcca_regs,
+ .pmac_regs = &rtw8852bt_pmac_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8852bt,
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 9ef469c1080e..cc278587b532 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -270,6 +270,54 @@ static const struct rtw89_edcca_regs rtw8852c_edcca_regs = {
.tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M,
};
+static const struct rtw89_pmac_regs rtw8852c_pmac_regs = {
+ .cck_txon = {R_CNT_CCKTXON, B_CNT_CCKTXON},
+ .cck_txen = {R_CNT_CCKTXEN, B_CNT_CCKTXEN},
+ .cck_cca = {R_CNT_CCK_CCA_P0, B_CNT_CCK_CCA_P0},
+ .cck_sfd_gg = {R_SFD_GG_CNT_V1, B_SFD_GG_CNT},
+ .cck_sig_gg = {R_SIG_GG_CNT_V1, B_SIG_GG_CNT_V1},
+ .cck_spoofing = {R_SPOOF_CNT_V1, B_SPOOF_CNT_V1},
+ .cck_brk = {R_BRK_CNT, B_BRK_CNT},
+ .brk = {R_CNT_BRK, B_CNT_BRK},
+ .brk_option = {R_BRK_OPT, B_BRK_OPT},
+ .search_fail = {R_CNT_SEARCH_FAIL, B_CNT_SEARCH_FAIL},
+ .lsig_brk_s_th = {R_CNT_LSIG_BRK_S_TH, B_CNT_LSIG_BRK_S_TH},
+ .lsig_brk_l_th = {R_CNT_LSIG_BRK_L_TH, B_CNT_LSIG_BRK_L_TH},
+ .rxl_err_parity = {R_CNT_RXL_ERR_PARITY, B_CNT_RXL_ERR_PARITY},
+ .rxl_err_rate = {R_CNT_RXL_ERR_RATE, B_CNT_RXL_ERR_RATE},
+ .ofdm_cca = {R_CNT_OFDM_CCA, B_CNT_OFDM_CCA},
+ .cca_spoofing = {R_CNT_CCA_SPOOFING, B_CNT_CCA_SPOOFING},
+ .ampdu_miss = {R_CNT_AMPDU_MISS, B_CNT_AMPDU_MISS},
+ .r1b_rx_rpt_rst = {R_R1B_RX_RPT_RST_V1, B_R1B_RX_RPT_RST_V1},
+ .r1b_rr_sel = {},
+ .enable_all_cnt = {R_ENABLE_ALL_CNT, B_ENABLE_ALL_CNT},
+ .rst_all_cnt = {R_RST_ALL_CNT, B_RST_ALL_CNT},
+ .cck_crc32 = R_CNT_CCK_CRC32_P0,
+ .cck_crc32_ok_mask = B_CNT_CCK_CRC32OK_P0,
+ .cck_crc32_fail_mask = B_CNT_CCK_CRC32FAIL_P0,
+ .ofdm_txon = R_CNT_OFDMTXON,
+ .ofdm_txon_mask = B_CNT_OFDMTXON,
+ .ofdm_txen_mask = B_CNT_OFDMTXEN,
+ .l_crc = R_CNT_L_CRC,
+ .l_crc_ok_mask = B_CNT_L_CRC_OK,
+ .l_crc_err_mask = B_CNT_L_CRC_ERR,
+ .ht_crc = R_CNT_HT_CRC,
+ .ht_crc_ok_mask = B_CNT_HT_CRC_OK,
+ .ht_crc_err_mask = B_CNT_HT_CRC_ERR,
+ .vht_crc = R_CNT_VHT_CRC,
+ .vht_crc_ok_mask = B_CNT_VHT_CRC_OK,
+ .vht_crc_err_mask = B_CNT_VHT_CRC_ERR,
+ .he_crc = R_CNT_HE_CRC,
+ .he_crc_ok_mask = B_CNT_HE_CRC_OK,
+ .he_crc_err_mask = B_CNT_HE_CRC_ERR,
+ .eht_crc = 0,
+ .eht_crc_ok_mask = 0,
+ .eht_crc_err_mask = 0,
+ .ampdu_crc = R_CNT_AMPDU_RX_CRC32,
+ .ampdu_crc_ok_mask = B_CNT_AMPDU_RX_CRC32_OK,
+ .ampdu_crc_err_mask = B_CNT_AMPDU_RX_CRC32_ERR,
+};
+
static void rtw8852c_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en,
enum rtw89_phy_idx phy_idx);
@@ -3252,6 +3300,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}},
.dma_ch_mask = 0,
.edcca_regs = &rtw8852c_edcca_regs,
+ .pmac_regs = &rtw8852c_pmac_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8852c,
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
index 3c453b93c52e..e6f15ee2a86b 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
@@ -383,6 +383,54 @@ static const struct rtw89_edcca_regs rtw8922a_edcca_regs = {
.tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_BE_M,
};
+static const struct rtw89_pmac_regs rtw8922a_pmac_regs = {
+ .cck_txon = {R_CNT_CCKTXON_V1, B_CNT_CCKTXON},
+ .cck_txen = {R_CNT_CCKTXEN_V1, B_CNT_CCKTXEN},
+ .cck_cca = {R_CNT_CCK_CCA_P0_V1, B_CNT_CCK_CCA_P0},
+ .cck_sfd_gg = {R_SFD_GG_CNT_V2, B_SFD_GG_CNT},
+ .cck_sig_gg = {R_SIG_GG_CNT_V2, B_SIG_GG_CNT_V1},
+ .cck_spoofing = {R_SPOOF_CNT_V2, B_SPOOF_CNT_V1},
+ .cck_brk = {R_BRK_CNT_V1, B_BRK_CNT},
+ .brk = {R_CNT_BRK_V1, B_CNT_BRK},
+ .brk_option = {},
+ .search_fail = {R_CNT_SEARCH_FAIL_V1, B_CNT_SEARCH_FAIL},
+ .lsig_brk_s_th = {R_CNT_LSIG_BRK_S_TH_V1, B_CNT_LSIG_BRK_S_TH},
+ .lsig_brk_l_th = {R_CNT_LSIG_BRK_L_TH_V1, B_CNT_LSIG_BRK_L_TH},
+ .rxl_err_parity = {R_CNT_RXL_ERR_PARITY_V1, B_CNT_RXL_ERR_PARITY},
+ .rxl_err_rate = {R_CNT_RXL_ERR_RATE_V1, B_CNT_RXL_ERR_RATE},
+ .ofdm_cca = {R_CNT_OFDM_CCA_V1, B_CNT_OFDM_CCA},
+ .cca_spoofing = {R_CNT_CCA_SPOOFING_V1, B_CNT_CCA_SPOOFING},
+ .ampdu_miss = {R_CNT_AMPDU_MISS_V1, B_CNT_AMPDU_MISS},
+ .r1b_rx_rpt_rst = {R_R1B_RX_RPT_RST_BE, B_R1B_RX_RPT_RST_V1},
+ .r1b_rr_sel = {},
+ .enable_all_cnt = {R_ENABLE_ALL_CNT, B_ENABLE_ALL_CNT},
+ .rst_all_cnt = {R_RST_ALL_CNT, B_RST_ALL_CNT},
+ .cck_crc32 = R_CNT_CCK_CRC32_P0_V1,
+ .cck_crc32_ok_mask = B_CNT_CCK_CRC32OK_P0,
+ .cck_crc32_fail_mask = B_CNT_CCK_CRC32FAIL_P0,
+ .ofdm_txon = R_CNT_OFDMTXON_V1,
+ .ofdm_txon_mask = B_CNT_OFDMTXON,
+ .ofdm_txen_mask = B_CNT_OFDMTXEN,
+ .l_crc = R_CNT_L_CRC_V1,
+ .l_crc_ok_mask = B_CNT_L_CRC_OK,
+ .l_crc_err_mask = B_CNT_L_CRC_ERR,
+ .ht_crc = R_CNT_HT_CRC_V1,
+ .ht_crc_ok_mask = B_CNT_HT_CRC_OK,
+ .ht_crc_err_mask = B_CNT_HT_CRC_ERR,
+ .vht_crc = R_CNT_VHT_CRC_V1,
+ .vht_crc_ok_mask = B_CNT_VHT_CRC_OK,
+ .vht_crc_err_mask = B_CNT_VHT_CRC_ERR,
+ .he_crc = R_CNT_HE_CRC_V1,
+ .he_crc_ok_mask = B_CNT_HE_CRC_OK,
+ .he_crc_err_mask = B_CNT_HE_CRC_ERR,
+ .eht_crc = R_CNT_EHT_CRC,
+ .eht_crc_ok_mask = B_CNT_EHT_CRC_OK,
+ .eht_crc_err_mask = B_CNT_EHT_CRC_ERR,
+ .ampdu_crc = R_CNT_AMPDU_RX_CRC32_V1,
+ .ampdu_crc_ok_mask = B_CNT_AMPDU_RX_CRC32_OK,
+ .ampdu_crc_err_mask = B_CNT_AMPDU_RX_CRC32_ERR,
+};
+
static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = {
[RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310},
[RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240},
@@ -3245,6 +3293,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
.btc_sb = {{{R_BE_SCOREBOARD, R_BE_SCOREBOARD},}},
.dma_ch_mask = 0,
.edcca_regs = &rtw8922a_edcca_regs,
+ .pmac_regs = &rtw8922a_pmac_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8922a,
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index ba736b967880..b8b75fca0a1b 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -227,6 +227,54 @@ static const struct rtw89_edcca_regs rtw8922d_edcca_regs = {
.tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_BE_M,
};
+static const struct rtw89_pmac_regs rtw8922d_pmac_regs = {
+ .cck_txon = {R_CNT_CCKTXON_BE4, B_CNT_CCKTXON},
+ .cck_txen = {R_CNT_CCKTXEN_BE4, B_CNT_CCKTXEN},
+ .cck_cca = {R_CNT_CCK_CCA_BE4, B_CNT_CCK_CCA_BE4},
+ .cck_sfd_gg = {R_SFD_GG_CNT_BE4, B_SFD_GG_CNT},
+ .cck_sig_gg = {R_SIG_GG_CNT_BE4, B_SIG_GG_CNT_V1},
+ .cck_spoofing = {R_SPOOF_CNT_BE4, B_SPOOF_CNT_V1},
+ .cck_brk = {R_BRK_CNT_BE4, B_BRK_CNT},
+ .brk = {R_CNT_BRK_BE4, B_CNT_BRK},
+ .brk_option = {},
+ .search_fail = {R_CNT_SEARCH_FAIL_BE4, B_CNT_SEARCH_FAIL},
+ .lsig_brk_s_th = {R_CNT_LSIG_BRK_S_TH_BE4, B_CNT_LSIG_BRK_S_TH},
+ .lsig_brk_l_th = {R_CNT_LSIG_BRK_L_TH_BE4, B_CNT_LSIG_BRK_L_TH},
+ .rxl_err_parity = {R_CNT_RXL_ERR_PARITY_BE4, B_CNT_RXL_ERR_PARITY},
+ .rxl_err_rate = {R_CNT_RXL_ERR_RATE_BE4, B_CNT_RXL_ERR_RATE},
+ .ofdm_cca = {R_CNT_OFDM_CCA_BE4, B_CNT_OFDM_CCA},
+ .cca_spoofing = {R_CNT_CCA_SPOOFING_BE4, B_CNT_CCA_SPOOFING},
+ .ampdu_miss = {R_CNT_AMPDU_MISS_BE4, B_CNT_AMPDU_MISS},
+ .r1b_rx_rpt_rst = {R_R1B_RX_RPT_RST_BE4, B_R1B_RX_RPT_RST_V1},
+ .r1b_rr_sel = {},
+ .enable_all_cnt = {R_ENABLE_ALL_CNT_BE4, B_ENABLE_ALL_CNT},
+ .rst_all_cnt = {R_RST_ALL_CNT_BE4, B_RST_ALL_CNT},
+ .cck_crc32 = R_CNT_CCK_CRC32_BE4,
+ .cck_crc32_ok_mask = B_CNT_CCK_CRC32OK_BE4,
+ .cck_crc32_fail_mask = B_CNT_CCK_CRC32FAIL_BE4,
+ .ofdm_txon = R_CNT_OFDMTXON_BE4,
+ .ofdm_txon_mask = B_CNT_OFDMTXON,
+ .ofdm_txen_mask = B_CNT_OFDMTXEN,
+ .l_crc = R_CNT_L_CRC_BE4,
+ .l_crc_ok_mask = B_CNT_L_CRC_OK,
+ .l_crc_err_mask = B_CNT_L_CRC_ERR,
+ .ht_crc = R_CNT_HT_CRC_BE4,
+ .ht_crc_ok_mask = B_CNT_HT_CRC_OK,
+ .ht_crc_err_mask = B_CNT_HT_CRC_ERR,
+ .vht_crc = R_CNT_VHT_CRC_BE4,
+ .vht_crc_ok_mask = B_CNT_VHT_CRC_OK,
+ .vht_crc_err_mask = B_CNT_VHT_CRC_ERR,
+ .he_crc = R_CNT_HE_CRC_BE4,
+ .he_crc_ok_mask = B_CNT_HE_CRC_OK,
+ .he_crc_err_mask = B_CNT_HE_CRC_ERR,
+ .eht_crc = R_CNT_EHT_CRC_BE4,
+ .eht_crc_ok_mask = B_CNT_EHT_CRC_OK,
+ .eht_crc_err_mask = B_CNT_EHT_CRC_ERR,
+ .ampdu_crc = R_CNT_AMPDU_RX_CRC32_BE4,
+ .ampdu_crc_ok_mask = B_CNT_AMPDU_RX_CRC32_OK,
+ .ampdu_crc_err_mask = B_CNT_AMPDU_RX_CRC32_ERR,
+};
+
static const struct rtw89_efuse_block_cfg rtw8922d_efuse_blocks[] = {
[RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310},
[RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240},
@@ -3085,6 +3133,7 @@ const struct rtw89_chip_info rtw8922d_chip_info = {
BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH7) |
BIT(RTW89_DMA_B0HI) | BIT(RTW89_DMA_B1HI),
.edcca_regs = &rtw8922d_edcca_regs,
+ .pmac_regs = &rtw8922d_pmac_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8922d,
#endif
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH rtw-next 5/7] wifi: rtw89: debug: extend bb_info with TX status and PER
2026-04-29 13:26 [PATCH rtw-next 0/7] wifi: rtw89: debug: introduce BB diagnosis Ping-Ke Shih
` (3 preceding siblings ...)
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 ` 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
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-04-29 13:26 UTC (permalink / raw)
To: linux-wireless; +Cc: damon.chen
From: Kuan-Chung Chen <damon.chen@realtek.com>
Enhance bb_info debugfs by adding TX status information to aid
debugging and performance analysis.
A snapshot of TX-related registers, including PPDU type and subtype,
bandwidth, TX power, STBC, etc. The information is collected per
PHY during track_work and displayed via bb_info debugfs.
TX status output:
== TX General
EHT_MU_SU DATA
BW: 160, TX_SC: 0, TX_PATH_EN: 3, PATH_MAP: 0xe4
TXPWR TMAC: 11, P0: 11, P1: 11 dBm
MCS: 9, STBC: 0
Info: [0x0000000b, 0xc1702c30, 0x0ff1e430, 0xc0000000, 0x99000009, 0x40000000]
Common ctrl: [0x00000150, 0x40190140]
In addition, include the retry ratio from RA reports and display it
as PER (packet error rate) in station debug information.
PER output:
TX rate [0, 0]: HE 2SS MCS-4 GI:0.8 BW:20 (hw_rate=0x324) PER:23
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.h | 24 +++
drivers/net/wireless/realtek/rtw89/debug.c | 206 ++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/phy.c | 93 ++++++++-
drivers/net/wireless/realtek/rtw89/phy.h | 23 +++
drivers/net/wireless/realtek/rtw89/phy_be.c | 46 +++++
drivers/net/wireless/realtek/rtw89/reg.h | 29 +++
6 files changed, 420 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 7f869a339ee6..e8b03716d41e 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3488,6 +3488,7 @@ struct rtw89_ra_report {
struct rate_info txrate;
u32 bit_rate;
u16 hw_rate;
+ u8 retry_ratio;
bool might_fallback_legacy;
};
@@ -4175,6 +4176,12 @@ struct rtw89_reg5_def {
u32 data;
};
+#define RTW89_REGS_DEF(x) {x, ARRAY_SIZE(x)}
+struct rtw89_regs_def {
+ const u32 *regs;
+ u32 reg_nr;
+};
+
struct rtw89_reg_imr {
u32 addr;
u32 clr;
@@ -5591,6 +5598,22 @@ struct rtw89_pmac_stat_info {
u32 cnt_sb_search_fail;
};
+struct rtw89_tx_stat_info {
+ u32 info[6];
+ u32 common_ctrl[2];
+ u32 txpwr[2];
+ u8 type;
+ u8 subtype;
+ u8 txcmd;
+ u8 txsc;
+ u8 bw;
+ u16 tmac_txpwr;
+ u8 tx_path_en;
+ u8 path_map;
+ u8 max_mcs;
+ bool stbc;
+};
+
struct rtw89_agc_gaincode_set {
u8 lna_idx;
u8 tia_idx;
@@ -6418,6 +6441,7 @@ struct rtw89_dev {
struct rtw89_pkt_stat cur_pkt_stat;
struct rtw89_pkt_stat last_pkt_stat;
struct rtw89_pmac_stat_info pmac_stat;
+ struct rtw89_tx_stat_info tx_stat;
} bbs[RTW89_PHY_NUM];
struct wiphy_delayed_work track_work;
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index d8a183bfc6da..d9a5bbae11f2 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -3926,6 +3926,7 @@ static int rtw89_sta_link_info_get_iter(struct rtw89_dev *rtwdev,
rtw89_rate_info_bw_to_mhz(rate->bw));
p += scnprintf(p, end - p, " (hw_rate=0x%x)",
rtwsta_link->ra_report.hw_rate);
+ p += scnprintf(p, end - p, " PER:%d", rtwsta_link->ra_report.retry_ratio);
p += scnprintf(p, end - p, " ==> agg_wait=%d (%d)\n",
rtwsta_link->max_agg_wait,
max_rc_amsdu_len);
@@ -4138,11 +4139,179 @@ static ssize_t rtw89_debug_priv_phy_info_get(struct rtw89_dev *rtwdev,
return p - buf;
}
+static const char *const lcck[] = {"L_CCK"};
+static const char *const scck[] = {"S_CCK"};
+static const char *const ht_gf[] = {"HT_GF"};
+static const char *const vht_mu[] = {"VHT_MU"};
+static const char *const he_er_su[] = {"HE_ER_SU"};
+static const char *const eht_tb[] = {"EHT_TB"};
+static const char *const legacy_ax[] = {"LEGACY"};
+static const char *const ht_ax[] = {"HT"};
+static const char *const vht_su_ax[] = {"VHT_SU"};
+static const char *const he_su_ax[] = {"HE_SU"};
+static const char *const he_mu_ax[] = {"HE_MU"};
+static const char *const he_tb_ax[] = {"HE_TB"};
+static const char *const legacy_be[] = {
+ "LEGACY", "LEGACY_DUP", "LEGACY_DUP_PUNC"
+};
+
+static const char *const ht_be[] = {
+ "HT_MF", "HT_SND_NDP"
+};
+
+static const char *const vht_su_be[] = {
+ "VHT_SU", "VHT_SND_NDP"
+};
+
+static const char *const he_su_be[] = {
+ "HE_SU", "HE_SND_NDP", "HE_SND_NDP_PUNC", "HE_RANG_NDP"
+};
+
+static const char *const he_mu_be[] = {
+ "HE_MU_RU", "HE_MU_MU", "HE_MU_RU_PUNC"
+};
+
+static const char *const he_tb_be[] = {
+ "HE_TB", "HE_TB_FB_NDP", "HE_MU_RANG_NDP"
+};
+
+static const char *const eht_mu[] = {
+ "EHT_MU_SU", "EHT_MU_ER", "EHT_MU_RU", "EHT_MU_MU",
+ "EHT_MU_SND_NDP", "EHT_MU_SU_PUNC", "EHT_MU_RU_PUNC",
+ "EHT_SND_NDP_PUNC", "EHT_MU_MU_PUNC"
+};
+
+#define PPDU_SAME(ppdu) \
+ {.str = {ppdu, ppdu}, \
+ .cnt = {ARRAY_SIZE(ppdu), ARRAY_SIZE(ppdu)} }
+#define PPDU_VARIANT(ppdu) \
+ {.str = {ppdu##_ax, ppdu##_be}, \
+ .cnt = {ARRAY_SIZE(ppdu##_ax), ARRAY_SIZE(ppdu##_be)} }
+#define PPDU_GEV1(ppdu) \
+ {.str = {NULL, ppdu}, \
+ .cnt = {0, ARRAY_SIZE(ppdu)} }
+
+static const struct rtw89_ppdu_info {
+ const char *const *str[RTW89_CHIP_GEN_NUM];
+ u8 cnt[RTW89_CHIP_GEN_NUM];
+} rtw89_ppdu_infos[] = {
+ [0] = PPDU_SAME(lcck),
+ [1] = PPDU_SAME(scck),
+ [2] = PPDU_VARIANT(legacy),
+ [3] = PPDU_VARIANT(ht),
+ [4] = PPDU_SAME(ht_gf),
+ [5] = PPDU_VARIANT(vht_su),
+ [6] = PPDU_SAME(vht_mu),
+ [7] = PPDU_VARIANT(he_su),
+ [8] = PPDU_SAME(he_er_su),
+ [9] = PPDU_VARIANT(he_mu),
+ [10] = PPDU_VARIANT(he_tb),
+ [11] = PPDU_GEV1(eht_mu),
+ [12] = PPDU_GEV1(eht_tb),
+};
+
+#define TXCMD_SAME(txcmd) {txcmd, txcmd}
+#define TXCMD_DIFF(txcmd, txcmd_v1) {txcmd, txcmd_v1}
+#define TXCMD_GEV1(txcmd) {"RSVD", txcmd}
+
+static const struct rtw89_txcmd_info {
+ const char *str[RTW89_CHIP_GEN_NUM];
+} rtw89_txcmd_infos[] = {
+ [0] = {TXCMD_SAME("DATA")},
+ [1] = {TXCMD_SAME("BCN")},
+ [2] = {TXCMD_SAME("HT_NDPA")},
+ [3] = {TXCMD_SAME("VHT_NDPA")},
+ [4] = {TXCMD_SAME("HE_NDPA")},
+ [5] = {TXCMD_GEV1("EHT_NDPA")},
+ [6] = {TXCMD_GEV1("11MC_FTM")},
+ [7] = {TXCMD_GEV1("11MC_FTM_ACK")},
+ [8] = {TXCMD_SAME("RTS")},
+ [9] = {TXCMD_SAME("CTS2S")},
+ [10] = {TXCMD_SAME("CF_END")},
+ [11] = {TXCMD_SAME("CMP_BAR")},
+ [12] = {TXCMD_SAME("BFRP")},
+ [13] = {TXCMD_SAME("NDP")},
+ [14] = {TXCMD_SAME("QoS_NULL")},
+ [15] = {TXCMD_GEV1("CTS_2_MURTS")},
+ [16] = {TXCMD_SAME("ACK")},
+ [17] = {TXCMD_SAME("CTS")},
+ [18] = {TXCMD_SAME("CMP_BA")},
+ [19] = {TXCMD_SAME("MSTA_BA")},
+ [20] = {TXCMD_SAME("HT_CSI")},
+ [21] = {TXCMD_SAME("VHT_CSI")},
+ [22] = {TXCMD_SAME("HE_CSI")},
+ [23] = {TXCMD_GEV1("EHT_CSI")},
+ [24] = {TXCMD_GEV1("NTB_I2R_NDPA")},
+ [25] = {TXCMD_GEV1("NTB_I2R_NDP")},
+ [26] = {TXCMD_GEV1("NTB_I2R_LMR")},
+ [27] = {TXCMD_GEV1("NTB_I2R_NDP")},
+ [28] = {TXCMD_GEV1("NTB_I2R_LMR")},
+ [29] = {TXCMD_GEV1("NTB_R2I_RANG_NDPA")},
+ [30] = {TXCMD_GEV1("NTB_R2I_NDP")},
+ [31] = {TXCMD_DIFF("TB_PPDU", "NTB_R2I_LMR")},
+ [32] = {TXCMD_SAME("TRIG_BASIC")},
+ [33] = {TXCMD_SAME("TRIG_BFRP")},
+ [34] = {TXCMD_SAME("TRIG_MUBAR")},
+ [35] = {TXCMD_SAME("TRIG_MURTS")},
+ [36] = {TXCMD_SAME("TRIG_BSRP")},
+ [37] = {TXCMD_SAME("TRIG_BQRP")},
+ [38] = {TXCMD_SAME("TRIG_NFRP")},
+ [39] = {TXCMD_GEV1("TRIG_BASIC_DATA")},
+ [40] = {TXCMD_GEV1("TRIG_RANG_POLL")},
+ [41] = {TXCMD_GEV1("TRIG_RANG_SNR")},
+ [42] = {TXCMD_GEV1("TRIG_RANG_LMR")},
+ [48] = {TXCMD_DIFF("TRIG_BASIC_DATA", "TRIG_TB_CSI")},
+ [49] = {TXCMD_GEV1("TRIG_TB_CBA")},
+ [50] = {TXCMD_GEV1("TRIG_TB_MBA")},
+ [51] = {TXCMD_GEV1("TRIG_TB_BSR")},
+ [52] = {TXCMD_GEV1("TRIG_TB_BQR")},
+ [53] = {TXCMD_GEV1("TRIG_TB_ACK")},
+ [54] = {TXCMD_GEV1("TRIG_TB_PPDU")},
+ [55] = {TXCMD_GEV1("TRIG_TB_I2R_CTS2S")},
+ [56] = {TXCMD_GEV1("TRIG_TB_I2R_NDP")},
+ [57] = {TXCMD_GEV1("TRIG_TB_I2R_LMR")},
+};
+
+static const char *rtw89_ppdu_str(struct rtw89_dev *rtwdev, u8 type, u8 subtype)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_ppdu_info *ppdu_info;
+
+ if (type > ARRAY_SIZE(rtw89_ppdu_infos))
+ return "RSVD";
+
+ ppdu_info = &rtw89_ppdu_infos[type];
+
+ if (!ppdu_info->str[chip->chip_gen] ||
+ subtype >= ppdu_info->cnt[chip->chip_gen])
+ return "RSVD";
+
+ return ppdu_info->str[chip->chip_gen][subtype];
+}
+
+static const char *rtw89_txcmd_str(struct rtw89_dev *rtwdev, u8 txcmd)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
+ if (txcmd < ARRAY_SIZE(rtw89_txcmd_infos))
+ return rtw89_txcmd_infos[txcmd].str[chip->chip_gen] ?: "RSVD";
+
+ return "RSVD";
+}
+
static int rtw89_get_bb_stat(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
char *buf, size_t bufsz)
{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ const struct rtw89_physts_regs *physts = phy->physts;
struct rtw89_pmac_stat_info *pmac = &bb->pmac_stat;
+ struct rtw89_tx_stat_info *tx_stat = &bb->tx_stat;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
char *p = buf, *end = buf + bufsz;
+ u8 factor = chip->txpwr_factor_rf;
+ u32 reg_nr;
+ s32 val;
+ int i;
p += scnprintf(p, end - p, "\n[PHY %u]\n", bb->phy_idx);
@@ -4178,6 +4347,43 @@ static int rtw89_get_bb_stat(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
pmac->cnt_sb_search_fail);
p += scnprintf(p, end - p, "AMPDU miss: %d\n\n", pmac->cnt_ampdu_miss);
+ p += scnprintf(p, end - p, "== TX General\n");
+ p += scnprintf(p, end - p, "%s %s\n",
+ rtw89_ppdu_str(rtwdev, tx_stat->type, tx_stat->subtype),
+ rtw89_txcmd_str(rtwdev, tx_stat->txcmd));
+
+ p += scnprintf(p, end - p, "BW: %d, TX_SC: %d, TX_PATH_EN: %d, PATH_MAP: 0x%x\n",
+ 20 << tx_stat->bw, tx_stat->txsc,
+ tx_stat->tx_path_en, tx_stat->path_map);
+
+ val = sign_extend32(tx_stat->tmac_txpwr, 8);
+ p += scnprintf(p, end - p, "TXPWR TMAC: %d,", val >> factor);
+
+ reg_nr = min(chip->rf_path_num, ARRAY_SIZE(tx_stat->txpwr));
+ for (i = 0; i < reg_nr; i++) {
+ val = sign_extend32(tx_stat->txpwr[i], 8);
+ p += scnprintf(p, end - p, " P%d: %d%s",
+ i, val >> factor, (i < reg_nr - 1) ? "," : "");
+ }
+ p += scnprintf(p, end - p, " dBm\n");
+
+ p += scnprintf(p, end - p, "MCS: %d, STBC: %d\n",
+ tx_stat->max_mcs, tx_stat->stbc);
+
+ p += scnprintf(p, end - p, "Info: [");
+ reg_nr = min(physts->tx_info.reg_nr, ARRAY_SIZE(tx_stat->info));
+ for (i = 0; i < reg_nr; i++)
+ p += scnprintf(p, end - p, "0x%08x%s",
+ tx_stat->info[i], (i < reg_nr - 1) ? ", " : "");
+ p += scnprintf(p, end - p, "]\n");
+
+ p += scnprintf(p, end - p, "Common ctrl: [");
+ reg_nr = min(physts->tx_common_ctrl.reg_nr, ARRAY_SIZE(tx_stat->common_ctrl));
+ for (i = 0; i < reg_nr; i++)
+ p += scnprintf(p, end - p, "0x%08x%s",
+ tx_stat->common_ctrl[i], (i < reg_nr - 1) ? ", " : "");
+ p += scnprintf(p, end - p, "]\n\n");
+
p += scnprintf(p, end - p, "== RSSI/RX Rate\n");
p += rtw89_get_rx_pkt_stat(rtwdev, bb, p, end - p);
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 80d358d80a38..cf7382e36b75 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -3239,6 +3239,7 @@ static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link,
bool format_v1 = chip->chip_gen == RTW89_CHIP_BE;
u8 mode, rate, bw, giltf, mac_id;
u16 legacy_bitrate, amsdu_len;
+ u8 retry_ratio = 0;
bool valid;
u8 mcs = 0;
u8 t;
@@ -3259,6 +3260,7 @@ static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link,
bw |= u8_encode_bits(t, BIT(2));
t = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MD_SEL_B2);
mode |= u8_encode_bits(t, BIT(2));
+ retry_ratio = le32_get_bits(c2h->w2, RTW89_C2H_RA_RPT_W2_RETRY_RATIO);
}
if (mode == RTW89_RA_RPT_MODE_LEGACY) {
@@ -3334,6 +3336,7 @@ static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link,
u16_encode_bits(rate, RTW89_HW_RATE_V1_MASK_VAL) :
u16_encode_bits(mode, RTW89_HW_RATE_MASK_MOD) |
u16_encode_bits(rate, RTW89_HW_RATE_MASK_VAL);
+ ra_report->retry_ratio = retry_ratio;
ra_report->might_fallback_legacy = mcs <= 2;
amsdu_len = get_max_amsdu_len(rtwdev, ra_report);
@@ -6034,6 +6037,71 @@ static void rtw89_phy_pmac_stat_update(struct rtw89_dev *rtwdev,
rtw89_phy_pmac_stat_reset(rtwdev, bb, cck);
}
+static void rtw89_phy_tx_stat_update(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ const struct rtw89_physts_regs *physts = phy->physts;
+ struct rtw89_tx_stat_info *tx_stat = &bb->tx_stat;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u32 reg_nr;
+ u32 val;
+ u32 i;
+
+ if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF &&
+ bb->phy_idx != RTW89_PHY_0)
+ val = 1;
+ else
+ val = 0;
+
+ rtw89_phy_write32_mask(rtwdev, physts->mac_phy_intf_sel.addr,
+ physts->mac_phy_intf_sel.mask, val);
+
+ reg_nr = min(physts->tx_info.reg_nr, ARRAY_SIZE(tx_stat->info));
+ for (i = 0; i < reg_nr; i++)
+ tx_stat->info[i] = rtw89_phy_read32(rtwdev, physts->tx_info.regs[i]);
+
+ reg_nr = min(physts->tx_common_ctrl.reg_nr, ARRAY_SIZE(tx_stat->common_ctrl));
+ for (i = 0; i < reg_nr; i++)
+ tx_stat->common_ctrl[i] =
+ rtw89_phy_read32(rtwdev, physts->tx_common_ctrl.regs[i]);
+
+ reg_nr = min(chip->rf_path_num, ARRAY_SIZE(tx_stat->txpwr));
+ for (i = 0; i < reg_nr; i++)
+ tx_stat->txpwr[i] = rtw89_phy_read32_mask(rtwdev, physts->txpwr[i].addr,
+ physts->txpwr[i].mask);
+
+ tx_stat->type = u32_get_bits(tx_stat->info[0], TX_STATUS_TYPE);
+
+ if (chip->chip_gen == RTW89_CHIP_AX) {
+ tx_stat->tx_path_en = u32_get_bits(tx_stat->info[0], TX_STATUS_TX_PATH_EN);
+ tx_stat->path_map = u32_get_bits(tx_stat->info[0], TX_STATUS_PATH_MAP);
+ tx_stat->txcmd = u32_get_bits(tx_stat->info[0], TX_STATUS_TXCMD);
+ tx_stat->txsc = u32_get_bits(tx_stat->info[1], TX_STATUS_TXSC);
+ tx_stat->bw = u32_get_bits(tx_stat->info[1], TX_STATUS_BW);
+ tx_stat->tmac_txpwr = u32_get_bits(tx_stat->info[1], TX_STATUS_TMAC_TXPWR);
+
+ if (!(chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)))
+ tx_stat->max_mcs = u32_get_bits(tx_stat->info[3], TX_STATUS_MAX_MCS);
+ } else {
+ tx_stat->type = u32_get_bits(tx_stat->info[0], TX_STATUS_TYPE);
+ tx_stat->subtype = u32_get_bits(tx_stat->info[0], TX_STATUS_SUBTYPE);
+
+ if (chip->chip_id == RTL8922A)
+ tx_stat->txcmd = u32_get_bits(tx_stat->info[0], TX_STATUS_TXCMD_V1);
+ else
+ tx_stat->txcmd = u32_get_bits(tx_stat->info[0], TX_STATUS_TXCMD_V2);
+
+ tx_stat->txsc = u32_get_bits(tx_stat->info[0], TX_STATUS_TXSC_V1);
+ tx_stat->bw = u32_get_bits(tx_stat->info[1], TX_STATUS_BW_V1);
+ tx_stat->tmac_txpwr = u32_get_bits(tx_stat->info[1], TX_STATUS_TMAC_TXPWR_V1);
+ tx_stat->tx_path_en = u32_get_bits(tx_stat->info[2], TX_STATUS_TX_PATH_EN_V1);
+ tx_stat->path_map = u32_get_bits(tx_stat->info[2], TX_STATUS_PATH_MAP_V1);
+ tx_stat->max_mcs = u32_get_bits(tx_stat->info[4], TX_STATUS_MAX_MCS_V1);
+ }
+
+ tx_stat->stbc = !!(tx_stat->common_ctrl[0] & TX_STATUS_STBC);
+}
+
static void rtw89_phy_trigger_tx_count(struct rtw89_dev *rtwdev)
{
if (RTW89_CHK_FW_FEATURE(TX_HISTORY_V1, &rtwdev->fw))
@@ -6051,8 +6119,10 @@ static void rtw89_phy_stat_update(struct rtw89_dev *rtwdev)
rtw89_phy_trigger_tx_count(rtwdev);
- rtw89_for_each_active_bb(rtwdev, bb)
+ rtw89_for_each_active_bb(rtwdev, bb) {
rtw89_phy_pmac_stat_update(rtwdev, bb);
+ rtw89_phy_tx_stat_update(rtwdev, bb);
+ }
}
void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
@@ -8702,10 +8772,31 @@ static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = {
.nhm_pwr_method_msk = B_NHM_PWDB_METHOD_MSK,
};
+static const u32 rtw89_txinfo_reg_ax[] = {
+ R_TX_INFO_0_0_COMB,
+ R_TX_INFO_0_1_COMB,
+ R_TX_INFO_1_0_COMB,
+ R_TX_INFO_1_1_COMB
+};
+
+static const u32 rtw89_tx_common_ctrl_reg_ax[] = {
+ R_TX_COMMON_CTRL_0_0_COMB,
+ R_TX_COMMON_CTRL_0_1_COMB
+};
+
+static const struct rtw89_reg_def rtw89_txpwr_ax[] = {
+ {.addr = R_PATH0_TXPWR, .mask = B_PATH0_TXPWR},
+ {.addr = R_PATH1_TXPWR, .mask = B_PATH1_TXPWR}
+};
+
static const struct rtw89_physts_regs rtw89_physts_regs_ax = {
.setting_addr = R_PLCP_HISTOGRAM,
.dis_trigger_fail_mask = B_STS_DIS_TRIG_BY_FAIL,
.dis_trigger_brk_mask = B_STS_DIS_TRIG_BY_BRK,
+ .mac_phy_intf_sel = {R_INTF_R_INTF_RPT_SEL, B_INTF_R_INTF_RPT_SEL},
+ .txpwr = rtw89_txpwr_ax,
+ .tx_info = RTW89_REGS_DEF(rtw89_txinfo_reg_ax),
+ .tx_common_ctrl = RTW89_REGS_DEF(rtw89_tx_common_ctrl_reg_ax),
};
static const struct rtw89_cfo_regs rtw89_cfo_regs_ax = {
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index c6761cedc5a5..830cabefca39 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -57,6 +57,25 @@
#define RA_MASK_EHT_4SS_MCS0_11 GENMASK_ULL(62, 60)
#define RA_MASK_EHT_RATES GENMASK_ULL(62, 12)
+#define TX_STATUS_TYPE GENMASK(3, 0)
+#define TX_STATUS_SUBTYPE GENMASK(7, 4)
+#define TX_STATUS_TXCMD GENMASK(29, 24)
+#define TX_STATUS_TXCMD_V1 GENMASK(13, 8)
+#define TX_STATUS_TXCMD_V2 GENMASK(15, 8)
+#define TX_STATUS_TXSC GENMASK(7, 4)
+#define TX_STATUS_TXSC_V1 GENMASK(27, 24)
+#define TX_STATUS_BW GENMASK(17, 16)
+#define TX_STATUS_BW_V1 GENMASK(6, 4)
+#define TX_STATUS_TMAC_TXPWR GENMASK(26, 18)
+#define TX_STATUS_TMAC_TXPWR_V1 GENMASK(16, 8)
+#define TX_STATUS_TX_PATH_EN GENMASK(15, 12)
+#define TX_STATUS_TX_PATH_EN_V1 GENMASK(7, 4)
+#define TX_STATUS_PATH_MAP GENMASK(23, 16)
+#define TX_STATUS_PATH_MAP_V1 GENMASK(15, 8)
+#define TX_STATUS_MAX_MCS GENMASK(7, 4)
+#define TX_STATUS_MAX_MCS_V1 GENMASK(3, 0)
+#define TX_STATUS_STBC BIT(0)
+
#define CFO_TRK_ENABLE_TH (2 << 2)
#define CFO_TRK_STOP_TH_4 (30 << 2)
#define CFO_TRK_STOP_TH_3 (20 << 2)
@@ -458,6 +477,10 @@ struct rtw89_physts_regs {
u32 setting_addr;
u32 dis_trigger_fail_mask;
u32 dis_trigger_brk_mask;
+ struct rtw89_reg_def mac_phy_intf_sel;
+ const struct rtw89_reg_def *txpwr;
+ struct rtw89_regs_def tx_info;
+ struct rtw89_regs_def tx_common_ctrl;
};
struct rtw89_cfo_regs {
diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c
index 25f1b068daa2..9caddd19384c 100644
--- a/drivers/net/wireless/realtek/rtw89/phy_be.c
+++ b/drivers/net/wireless/realtek/rtw89/phy_be.c
@@ -135,16 +135,62 @@ static const struct rtw89_ccx_regs rtw89_ccx_regs_be_v1 = {
.ifs_total_mask = B_IFS_TOTAL_BE4,
};
+static const u32 rtw89_tx_info_reg_be[] = {
+ R_TX_INFO_0_0_COMB_V1,
+ R_TX_INFO_0_1_COMB_V1,
+ R_TX_INFO_1_0_COMB_V1,
+ R_TX_INFO_1_1_COMB_V1,
+ R_TX_INFO_2_0_COMB_V1,
+ R_TX_INFO_2_1_COMB_V1
+};
+
+static const u32 rtw89_tx_common_ctrl_reg_be[] = {
+ R_TX_COMMON_CTRL_0_0_COMB_V1,
+ R_TX_COMMON_CTRL_0_1_COMB_V1
+};
+
+static const struct rtw89_reg_def rtw89_txpwr_be[] = {
+ {.addr = R_PATH0_TXPWR_V1, .mask = B_PATH0_TXPWR},
+ {.addr = R_PATH1_TXPWR_V1, .mask = B_PATH1_TXPWR}
+};
+
static const struct rtw89_physts_regs rtw89_physts_regs_be = {
.setting_addr = R_PLCP_HISTOGRAM,
.dis_trigger_fail_mask = B_STS_DIS_TRIG_BY_FAIL,
.dis_trigger_brk_mask = B_STS_DIS_TRIG_BY_BRK,
+ .mac_phy_intf_sel = {R_INTF_R_INTF_RPT_SEL, B_INTF_R_INTF_RPT_SEL},
+ .txpwr = rtw89_txpwr_be,
+ .tx_info = RTW89_REGS_DEF(rtw89_tx_info_reg_be),
+ .tx_common_ctrl = RTW89_REGS_DEF(rtw89_tx_common_ctrl_reg_be),
+};
+
+static const u32 rtw89_tx_info_reg_be_v1[] = {
+ R_TX_INFO_0_0_COMB_BE4,
+ R_TX_INFO_0_1_COMB_BE4,
+ R_TX_INFO_1_0_COMB_BE4,
+ R_TX_INFO_1_1_COMB_BE4,
+ R_TX_INFO_2_0_COMB_BE4,
+ R_TX_INFO_2_1_COMB_BE4
+};
+
+static const u32 rtw89_tx_common_ctrl_reg_be_v1[] = {
+ R_TX_COMMON_CTRL_0_0_COMB_BE4,
+ R_TX_COMMON_CTRL_0_1_COMB_BE4
+};
+
+static const struct rtw89_reg_def rtw89_txpwr_be_v1[] = {
+ {.addr = R_PATH0_TXPWR_BE4, .mask = B_PATH0_TXPWR},
+ {.addr = R_PATH1_TXPWR_BE4, .mask = B_PATH1_TXPWR}
};
static const struct rtw89_physts_regs rtw89_physts_regs_be_v1 = {
.setting_addr = R_PLCP_HISTOGRAM_BE_V1,
.dis_trigger_fail_mask = B_STS_DIS_TRIG_BY_FAIL,
.dis_trigger_brk_mask = B_STS_DIS_TRIG_BY_BRK,
+ .mac_phy_intf_sel = {R_INTF_R_INTF_RPT_SEL_BE4, B_INTF_R_INTF_RPT_SEL},
+ .txpwr = rtw89_txpwr_be_v1,
+ .tx_info = RTW89_REGS_DEF(rtw89_tx_info_reg_be_v1),
+ .tx_common_ctrl = RTW89_REGS_DEF(rtw89_tx_common_ctrl_reg_be_v1),
};
static const struct rtw89_cfo_regs rtw89_cfo_regs_be = {
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index c054a402bd20..f5151e1ad58d 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -8741,6 +8741,9 @@
#define B_DFS_FFT_EN BIT(0)
#define R_CHINFO_DATA 0x00C0
#define B_CHINFO_DATA_BITMAP GENMASK(22, 0)
+#define R_INTF_R_INTF_RPT_SEL 0x0200
+#define R_INTF_R_INTF_RPT_SEL_BE4 0x20200
+#define B_INTF_R_INTF_RPT_SEL BIT(12)
#define R_ANAPAR_PW15 0x030C
#define B_ANAPAR_PW15 GENMASK(31, 24)
#define B_ANAPAR_PW15_H GENMASK(27, 24)
@@ -9042,6 +9045,20 @@
#define B_SWSI_W_BUSY_V1 BIT(24)
#define B_SWSI_R_BUSY_V1 BIT(25)
#define B_SWSI_R_DATA_DONE_V1 BIT(26)
+#define R_TX_INFO_0_0_COMB 0x1800
+#define R_TX_INFO_0_0_COMB_V1 0x3E00
+#define R_TX_INFO_0_1_COMB 0x1804
+#define R_TX_INFO_0_1_COMB_V1 0x3E04
+#define R_TX_INFO_1_0_COMB 0x1808
+#define R_TX_INFO_1_0_COMB_V1 0x3E08
+#define R_TX_INFO_1_1_COMB 0x180C
+#define R_TX_INFO_1_1_COMB_V1 0x3E0C
+#define R_TX_INFO_2_0_COMB_V1 0x3E10
+#define R_TX_INFO_2_1_COMB_V1 0x3E14
+#define R_TX_COMMON_CTRL_0_0_COMB 0x1810
+#define R_TX_COMMON_CTRL_0_0_COMB_V1 0x3E20
+#define R_TX_COMMON_CTRL_0_1_COMB 0x1814
+#define R_TX_COMMON_CTRL_0_1_COMB_V1 0x3E24
#define R_CNT_LSIG_BRK_S_TH 0x1A00
#define R_CNT_LSIG_BRK_S_TH_V1 0x0E00
#define R_CNT_LSIG_BRK_S_TH_BE4 0x20E00
@@ -9184,6 +9201,8 @@
#define B_TXAGC_BB GENMASK(31, 24)
#define B_TXAGC_RF GENMASK(5, 0)
#define R_PATH0_TXPWR 0x1C78
+#define R_PATH0_TXPWR_V1 0xEE0C
+#define R_PATH0_TXPWR_BE4 0x2F90C
#define B_PATH0_TXPWR GENMASK(8, 0)
#define R_S0_ADDCK 0x1E00
#define B_S0_ADDCK_I GENMASK(9, 0)
@@ -9328,6 +9347,8 @@
#define B_TXAGC_BB_S1_OFT GENMASK(31, 16)
#define B_TXAGC_BB_S1 GENMASK(31, 24)
#define R_PATH1_TXPWR 0x3C78
+#define R_PATH1_TXPWR_V1 0xEF0C
+#define R_PATH1_TXPWR_BE4 0x2FA0C
#define B_PATH1_TXPWR GENMASK(8, 0)
#define R_S1_ADDCK 0x3E00
#define B_S1_ADDCK_I GENMASK(9, 0)
@@ -10813,6 +10834,14 @@
#define B_SW_SI_R_BUSY_BE4 BIT(25)
#define B_SW_SI_READ_DATA_DONE_BE4 BIT(26)
+#define R_TX_INFO_0_0_COMB_BE4 0x2DF00
+#define R_TX_INFO_0_1_COMB_BE4 0x2DF04
+#define R_TX_INFO_1_0_COMB_BE4 0x2DF08
+#define R_TX_INFO_1_1_COMB_BE4 0x2DF0C
+#define R_TX_INFO_2_0_COMB_BE4 0x2DF10
+#define R_TX_INFO_2_1_COMB_BE4 0x2DF14
+#define R_TX_COMMON_CTRL_0_0_COMB_BE4 0x2DF20
+#define R_TX_COMMON_CTRL_0_1_COMB_BE4 0x2DF24
#define R_RX_PATH0_TBL0_BE4 0x2E028
#define R_RX_PATH1_TBL0_BE4 0x2E128
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH rtw-next 6/7] wifi: rtw89: debug: add RX statistics in bb_info
2026-04-29 13:26 [PATCH rtw-next 0/7] wifi: rtw89: debug: introduce BB diagnosis Ping-Ke Shih
` (4 preceding siblings ...)
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 ` Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 7/7] wifi: rtw89: debug: add BB diagnose Ping-Ke Shih
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-04-29 13:26 UTC (permalink / raw)
To: linux-wireless; +Cc: damon.chen
From: Kuan-Chung Chen <damon.chen@realtek.com>
Expand RX packet statistics including coding type, spatial
diversity, and beamforming. These statistics are accumulated
per PHY and displayed in bb_info debugfs.
RX statistics output:
== RX General
LDPC: 190, BCC: 0, STBC: 0, SU_NON_BF: 0, SU_BF: 190, MU: 0
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 | 26 +++++++++++++++++-----
drivers/net/wireless/realtek/rtw89/core.h | 10 +++++++++
drivers/net/wireless/realtek/rtw89/debug.c | 8 +++++++
drivers/net/wireless/realtek/rtw89/txrx.h | 2 ++
4 files changed, 41 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index d8f83623e54a..b85728ceb63c 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -2097,11 +2097,8 @@ static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev,
u32 t;
phy_ppdu->chan_idx = le32_get_bits(ie->w0, RTW89_PHY_STS_IE01_W0_CH_IDX);
-
- if (rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR) {
- phy_ppdu->ldpc = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_LDPC);
- phy_ppdu->stbc = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_STBC);
- }
+ phy_ppdu->ldpc = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_LDPC);
+ phy_ppdu->stbc = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_STBC);
if (!phy_ppdu->hdr_2_en)
phy_ppdu->rx_path_en =
@@ -2114,9 +2111,11 @@ static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev,
return;
phy_ppdu->rpl_avg = le32_get_bits(ie->w0, RTW89_PHY_STS_IE01_W0_RSSI_AVG_FD);
+ phy_ppdu->su = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_SU);
phy_ppdu->ofdm.avg_snr = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_AVG_SNR);
phy_ppdu->ofdm.evm_max = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_EVM_MAX);
phy_ppdu->ofdm.evm_min = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_EVM_MIN);
+ phy_ppdu->bf = le32_get_bits(ie->w3, RTW89_PHY_STS_IE01_W3_BF);
phy_ppdu->ofdm.has = true;
/* sign conversion for S(12,2) */
@@ -3062,6 +3061,23 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
if (desc_info->data_rate < RTW89_HW_RATE_NR)
pkt_stat->rx_rate_cnt[desc_info->data_rate]++;
+ if (phy_ppdu && phy_ppdu->ofdm.has) {
+ if (phy_ppdu->ldpc)
+ pkt_stat->rx.ldpc++;
+ else
+ pkt_stat->rx.bcc++;
+
+ if (phy_ppdu->stbc)
+ pkt_stat->rx.stbc++;
+
+ if (!phy_ppdu->su)
+ pkt_stat->rx.mu++;
+ else if (phy_ppdu->bf)
+ pkt_stat->rx.su_bf++;
+ else
+ pkt_stat->rx.su_non_bf++;
+ }
+
rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, false, false);
out:
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index e8b03716d41e..c0e176c4c3a6 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -855,8 +855,10 @@ struct rtw89_rx_phy_ppdu {
} ofdm;
bool has_data;
bool has_bcn;
+ bool su;
bool ldpc;
bool stbc;
+ bool bf;
bool to_self;
bool valid;
bool hdr_2_en;
@@ -5378,6 +5380,14 @@ struct rtw89_pkt_stat {
u8 beacon_rate;
u32 beacon_len;
u32 rx_rate_cnt[RTW89_HW_RATE_NR];
+ struct {
+ u32 ldpc;
+ u32 bcc;
+ u32 stbc;
+ u32 su_bf;
+ u32 su_non_bf;
+ u32 mu;
+ } rx;
};
#define RTW89_BCN_TRACK_STAT_NR 32
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index d9a5bbae11f2..103948aee5cb 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -4303,6 +4303,7 @@ static int rtw89_get_bb_stat(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
char *buf, size_t bufsz)
{
const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_pkt_stat *pkt_stat = &bb->last_pkt_stat;
const struct rtw89_physts_regs *physts = phy->physts;
struct rtw89_pmac_stat_info *pmac = &bb->pmac_stat;
struct rtw89_tx_stat_info *tx_stat = &bb->tx_stat;
@@ -4384,6 +4385,13 @@ static int rtw89_get_bb_stat(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
tx_stat->common_ctrl[i], (i < reg_nr - 1) ? ", " : "");
p += scnprintf(p, end - p, "]\n\n");
+ p += scnprintf(p, end - p, "== RX General\n");
+ p += scnprintf(p, end - p,
+ "LDPC: %d, BCC: %d, STBC: %d, SU_NON_BF: %d, SU_BF: %d, MU: %d\n\n",
+ pkt_stat->rx.ldpc, pkt_stat->rx.bcc,
+ pkt_stat->rx.stbc, pkt_stat->rx.su_non_bf,
+ pkt_stat->rx.su_bf, pkt_stat->rx.mu);
+
p += scnprintf(p, end - p, "== RSSI/RX Rate\n");
p += rtw89_get_rx_pkt_stat(rtwdev, bb, p, end - p);
diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h
index b69a2529aefc..125ba2a9f145 100644
--- a/drivers/net/wireless/realtek/rtw89/txrx.h
+++ b/drivers/net/wireless/realtek/rtw89/txrx.h
@@ -634,8 +634,10 @@ struct rtw89_phy_sts_ie01 {
#define RTW89_PHY_STS_IE01_W2_AVG_SNR GENMASK(5, 0)
#define RTW89_PHY_STS_IE01_W2_EVM_MAX GENMASK(15, 8)
#define RTW89_PHY_STS_IE01_W2_EVM_MIN GENMASK(23, 16)
+#define RTW89_PHY_STS_IE01_W2_SU BIT(27)
#define RTW89_PHY_STS_IE01_W2_LDPC BIT(28)
#define RTW89_PHY_STS_IE01_W2_STBC BIT(30)
+#define RTW89_PHY_STS_IE01_W3_BF BIT(8)
struct rtw89_phy_sts_ie01_v2 {
__le32 w0;
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH rtw-next 7/7] wifi: rtw89: debug: add BB diagnose
2026-04-29 13:26 [PATCH rtw-next 0/7] wifi: rtw89: debug: introduce BB diagnosis Ping-Ke Shih
` (5 preceding siblings ...)
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 ` Ping-Ke Shih
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-04-29 13:26 UTC (permalink / raw)
To: linux-wireless; +Cc: damon.chen
From: Kuan-Chung Chen <damon.chen@realtek.com>
Add BB diagnostic to track potential abnormal conditions. Currently,
five diagnostic metrics are monitored: 1) Hang detection monitors
consecutive absence of TX and RX activity. 2) PD maximum triggers
when PD stays at its maximum threshold for a period. 3) No RX
occurs when no CCA activity is detected over multiple consecutive
cycles. 4) High FA indicates a high false alarm ratio, reflecting
severe environmental interference. 5) EDCCA alerts when high EDCCA
ratio, signaling a potential TX hang.
These metrics are exposed via debugfs diag_bb.
Output:
[PHY 0]
Diag bitmap = 0x0
Event{Hang, PD MAX, No RX, High FA, High EDCCA Ratio} = {0, 0, 0, 0, 0}
consecutive_no_tx_cnt=0, consecutive_no_rx_cnt=0
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.h | 23 ++++
drivers/net/wireless/realtek/rtw89/debug.c | 43 ++++++
drivers/net/wireless/realtek/rtw89/phy.c | 144 +++++++++++++++++++-
drivers/net/wireless/realtek/rtw89/phy.h | 4 +
drivers/net/wireless/realtek/rtw89/phy_be.c | 8 ++
drivers/net/wireless/realtek/rtw89/reg.h | 8 ++
6 files changed, 227 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index c0e176c4c3a6..bccfee7535a7 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -5578,6 +5578,7 @@ struct rtw89_pmac_stat_info {
u32 ofdm_phy_txon;
u32 cnt_ofdm_cca;
u32 cnt_cck_cca;
+ u32 cnt_cca_all;
u32 cnt_cck_spoofing;
u32 cnt_ofdm_spoofing;
u32 cnt_ampdu_miss;
@@ -5601,6 +5602,7 @@ struct rtw89_pmac_stat_info {
u32 cnt_sig_gg;
u32 cnt_cck_fail;
u32 cnt_ofdm_fail;
+ u32 cnt_fail_all;
u32 cnt_lsig_brk_s_th;
u32 cnt_lsig_brk_l_th;
u32 cnt_parity_fail;
@@ -5624,6 +5626,23 @@ struct rtw89_tx_stat_info {
bool stbc;
};
+enum rtw89_diag_bb_type {
+ RTW89_DIAG_BB_HANG,
+ RTW89_DIAG_BB_PD,
+ RTW89_DIAG_BB_NO_RX,
+ RTW89_DIAG_BB_FA,
+ RTW89_DIAG_BB_EDCCA,
+
+ RTW89_DIAG_BB_NR,
+};
+
+struct rtw89_diag_bb {
+ u32 diag_bb_bitmap; /* bitmap of enum rtw89_diag_bb_type */
+ u32 diag_bb_cnt[RTW89_DIAG_BB_NR];
+ u16 consecutive_no_tx_cnt;
+ u16 consecutive_no_rx_cnt;
+};
+
struct rtw89_agc_gaincode_set {
u8 lna_idx;
u8 tia_idx;
@@ -5639,6 +5658,7 @@ struct rtw89_dig_info {
struct rtw89_agc_gaincode_set cur_gaincode;
bool force_gaincode_idx_en;
struct rtw89_agc_gaincode_set force_gaincode;
+ enum rtw89_dig_noisy_level noisy_lv;
u8 igi_rssi_th[IGI_RSSI_TH_NUM];
u16 fa_th[FA_TH_NUM];
u8 igi_rssi;
@@ -5648,6 +5668,7 @@ struct rtw89_dig_info {
u8 dyn_igi_min;
bool dyn_pd_th_en;
u8 dyn_pd_th_max;
+ u8 dyn_pd_max_cnt;
u8 pd_low_th_ofst;
u8 ib_pbk;
s8 ib_pkpwr;
@@ -5912,6 +5933,7 @@ struct rtw89_env_monitor_info {
u8 nhm_th[RTW89_NHM_RPT_NUM];
struct rtw89_nhm_report *nhm_his[RTW89_BAND_NUM];
struct list_head nhm_rpt_list;
+ u8 edcca_clm_ratio;
};
enum rtw89_ser_rcvy_step {
@@ -6452,6 +6474,7 @@ struct rtw89_dev {
struct rtw89_pkt_stat last_pkt_stat;
struct rtw89_pmac_stat_info pmac_stat;
struct rtw89_tx_stat_info tx_stat;
+ struct rtw89_diag_bb diag;
} bbs[RTW89_PHY_NUM];
struct wiphy_delayed_work track_work;
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index 103948aee5cb..597052261974 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -92,6 +92,7 @@ struct rtw89_debugfs {
struct rtw89_debugfs_priv mlo_mode;
struct rtw89_debugfs_priv beacon_info;
struct rtw89_debugfs_priv diag_mac;
+ struct rtw89_debugfs_priv diag_bb;
};
struct rtw89_debugfs_iter_data {
@@ -5214,6 +5215,46 @@ rtw89_debug_priv_diag_mac_get(struct rtw89_dev *rtwdev,
return rtw89_mac_diag_iter_all(rtwdev, buf, bufsz);
}
+static int rtw89_get_diag_bb(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
+ char *buf, size_t bufsz)
+{
+ struct rtw89_diag_bb *diag = &bb->diag;
+ char *p = buf, *end = buf + bufsz;
+
+ p += scnprintf(p, end - p, "[PHY %u]\n", bb->phy_idx);
+ p += scnprintf(p, end - p, "Diag bitmap = 0x%x\n", diag->diag_bb_bitmap);
+ p += scnprintf(p, end - p,
+ "Event{Hang, PD MAX, No RX, High FA, High EDCCA Ratio} = ");
+ p += scnprintf(p, end - p, "{%d, %d, %d, %d, %d}\n",
+ diag->diag_bb_cnt[RTW89_DIAG_BB_HANG],
+ diag->diag_bb_cnt[RTW89_DIAG_BB_PD],
+ diag->diag_bb_cnt[RTW89_DIAG_BB_NO_RX],
+ diag->diag_bb_cnt[RTW89_DIAG_BB_FA],
+ diag->diag_bb_cnt[RTW89_DIAG_BB_EDCCA]);
+ p += scnprintf(p, end - p,
+ "consecutive_no_tx_cnt=%d, consecutive_no_rx_cnt=%d\n\n",
+ diag->consecutive_no_tx_cnt,
+ diag->consecutive_no_rx_cnt);
+
+ return p - buf;
+}
+
+static ssize_t
+rtw89_debug_priv_diag_bb_get(struct rtw89_dev *rtwdev,
+ struct rtw89_debugfs_priv *debugfs_priv,
+ char *buf, size_t bufsz)
+{
+ char *p = buf, *end = buf + bufsz;
+ struct rtw89_bb_ctx *bb;
+
+ lockdep_assert_wiphy(rtwdev->hw->wiphy);
+
+ rtw89_for_each_active_bb(rtwdev, bb)
+ p += rtw89_get_diag_bb(rtwdev, bb, p, end - p);
+
+ return p - buf;
+}
+
static int rtw89_get_beacon_info(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
char *buf, size_t bufsz)
{
@@ -5348,6 +5389,7 @@ static const struct rtw89_debugfs rtw89_debugfs_templ = {
.mlo_mode = rtw89_debug_priv_set_and_get(mlo_mode, RWLOCK),
.beacon_info = rtw89_debug_priv_get(beacon_info),
.diag_mac = rtw89_debug_priv_get(diag_mac, RSIZE_16K, RLOCK),
+ .diag_bb = rtw89_debug_priv_get(diag_bb, RSIZE_8K, RLOCK),
};
#define rtw89_debugfs_add(name, mode, fopname, parent) \
@@ -5398,6 +5440,7 @@ void rtw89_debugfs_add_sec1(struct rtw89_dev *rtwdev, struct dentry *debugfs_top
rtw89_debugfs_add_rw(mlo_mode);
rtw89_debugfs_add_r(beacon_info);
rtw89_debugfs_add_r(diag_mac);
+ rtw89_debugfs_add_r(diag_bb);
}
void rtw89_debugfs_init(struct rtw89_dev *rtwdev)
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index cf7382e36b75..f98a77f9fc1a 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -5847,6 +5847,50 @@ static void rtw89_phy_stat_init(struct rtw89_dev *rtwdev)
rtwdev->hal.thermal_prot_lv = 0;
}
+static void rtw89_phy_pmac_diag(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+#define RTW89_DIAG_BB_FA_RATIO_TH 80
+#define RTW89_DIAG_BB_NO_RX_TH 5
+#define RTW89_DIAG_BB_HANG_TH 30
+ struct rtw89_pmac_stat_info *pmac_stat = &bb->pmac_stat;
+ bool is_linked = rtwdev->total_sta_assoc > 0;
+ struct rtw89_diag_bb *diag = &bb->diag;
+ u8 fa_ratio = 0;
+
+ if (!(pmac_stat->cck_mac_txen || pmac_stat->ofdm_mac_txen))
+ diag->consecutive_no_tx_cnt++;
+ else
+ diag->consecutive_no_tx_cnt = 0;
+
+ if (!pmac_stat->cnt_cca_all)
+ diag->consecutive_no_rx_cnt++;
+ else
+ diag->consecutive_no_rx_cnt = 0;
+
+ if (pmac_stat->cnt_cca_all)
+ fa_ratio = pmac_stat->cnt_fail_all * PERCENT / pmac_stat->cnt_cca_all;
+
+ diag->diag_bb_bitmap &= ~(BIT(RTW89_DIAG_BB_NO_RX) |
+ BIT(RTW89_DIAG_BB_HANG) |
+ BIT(RTW89_DIAG_BB_FA));
+
+ if (diag->consecutive_no_rx_cnt >= RTW89_DIAG_BB_NO_RX_TH && is_linked) {
+ diag->diag_bb_bitmap |= BIT(RTW89_DIAG_BB_NO_RX);
+ diag->diag_bb_cnt[RTW89_DIAG_BB_NO_RX]++;
+ }
+
+ if (fa_ratio >= RTW89_DIAG_BB_FA_RATIO_TH && is_linked) {
+ diag->diag_bb_bitmap |= BIT(RTW89_DIAG_BB_FA);
+ diag->diag_bb_cnt[RTW89_DIAG_BB_FA]++;
+ }
+
+ if (diag->consecutive_no_tx_cnt > RTW89_DIAG_BB_HANG_TH &&
+ diag->consecutive_no_rx_cnt > RTW89_DIAG_BB_HANG_TH) {
+ diag->diag_bb_bitmap |= BIT(RTW89_DIAG_BB_HANG);
+ diag->diag_bb_cnt[RTW89_DIAG_BB_HANG]++;
+ }
+}
+
static void rtw89_phy_pmac_stat_reset(struct rtw89_dev *rtwdev,
struct rtw89_bb_ctx *bb, bool cck)
{
@@ -6017,6 +6061,14 @@ static void rtw89_phy_pmac_stat_update(struct rtw89_dev *rtwdev,
rtw89_phy_pmac_stat_ofdm(rtwdev, bb);
+ pmac->cnt_fail_all = pmac->cnt_ofdm_fail;
+ pmac->cnt_cca_all = pmac->cnt_ofdm_cca;
+
+ if (cck) {
+ pmac->cnt_fail_all += pmac->cnt_cck_fail;
+ pmac->cnt_cca_all += pmac->cnt_cck_cca;
+ }
+
pmac->cnt_crc32_error_all = pmac->cnt_he_crc32_error +
pmac->cnt_vht_crc32_error +
pmac->cnt_ht_crc32_error +
@@ -6034,6 +6086,7 @@ static void rtw89_phy_pmac_stat_update(struct rtw89_dev *rtwdev,
pmac->cnt_crc32_ok_all += pmac->cnt_eht_crc32_ok;
}
+ rtw89_phy_pmac_diag(rtwdev, bb);
rtw89_phy_pmac_stat_reset(rtwdev, bb, cck);
}
@@ -6722,6 +6775,29 @@ static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev,
return true;
}
+static bool rtw89_phy_edcca_clm_get_result(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
+{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
+ u32 val;
+
+ val = rtw89_phy_read32_idx(rtwdev, ccx->edcca_clm_rdy,
+ ccx->edcca_clm_rdy_mask, bb->phy_idx);
+ if (!val) {
+ rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
+ "Get EDCCA_CLM report Fail\n");
+ return false;
+ }
+
+ val = rtw89_phy_read32_idx(rtwdev, ccx->edcca_clm_cnt,
+ ccx->edcca_clm_cnt_mask, bb->phy_idx);
+ env->edcca_clm_ratio = rtw89_phy_ccx_get_report(rtwdev, bb, val, PERCENT);
+
+ return true;
+}
+
static void rtw89_phy_nhm_th_update(struct rtw89_dev *rtwdev,
struct rtw89_bb_ctx *bb)
{
@@ -6889,6 +6965,9 @@ static void __rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev,
if (rtw89_phy_ifs_clm_get_result(rtwdev, bb))
env->ccx_watchdog_result |= RTW89_PHY_ENV_MON_IFS_CLM;
+ if (rtw89_phy_edcca_clm_get_result(rtwdev, bb))
+ env->ccx_watchdog_result |= RTW89_PHY_ENV_MON_EDCCA_CLM;
+
rtw89_phy_ccx_racing_release(rtwdev, bb);
para.mntr_time = 1900;
para.rac_lv = RTW89_RAC_LV_1;
@@ -7195,6 +7274,7 @@ static void rtw89_phy_dig_para_reset(struct rtw89_dev *rtwdev,
dig->dyn_igi_max = igi_max_performance_mode;
dig->dyn_igi_min = dynamic_igi_min;
dig->dyn_pd_th_max = dynamic_pd_threshold_max;
+ dig->dyn_pd_max_cnt = 0;
dig->pd_low_th_ofst = pd_low_th_offset;
dig->is_linked_pre = false;
}
@@ -7318,6 +7398,7 @@ static void rtw89_phy_dig_igi_offset_by_env(struct rtw89_dev *rtwdev,
igi_offset = min_t(u8, igi_offset, IGI_OFFSET_MAX);
dig->fa_rssi_ofst = igi_offset;
+ dig->noisy_lv = noisy_lv;
rtw89_debug(rtwdev, RTW89_DBG_DIG,
"fa_th: [+6 (%d) +4 (%d) +2 (%d) 0 (%d) -2 ]\n",
@@ -7548,10 +7629,33 @@ void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
rtw89_phy_dig_update_para(rtwdev, bb);
}
+static void rtw89_phy_dig_diag(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, bool is_linked)
+{
+#define RTW89_DIAG_BB_PD_MAX_PERIOD 5
+ struct rtw89_diag_bb *diag = &bb->diag;
+ struct rtw89_dig_info *dig = &bb->dig;
+
+ diag->diag_bb_bitmap &= ~BIT(RTW89_DIAG_BB_PD);
+
+ if (dig->dyn_igi_max != dig->igi_fa_rssi ||
+ dig->noisy_lv < RTW89_DIG_NOISY_LEVEL_MAX) {
+ dig->dyn_pd_max_cnt = 0;
+ return;
+ }
+
+ if (++dig->dyn_pd_max_cnt < RTW89_DIAG_BB_PD_MAX_PERIOD || !is_linked)
+ return;
+
+ diag->diag_bb_bitmap |= BIT(RTW89_DIAG_BB_PD);
+ diag->diag_bb_cnt[RTW89_DIAG_BB_PD]++;
+}
+
#define IGI_RSSI_MIN 10
#define ABS_IGI_MIN 0xc
static
-void rtw89_phy_cal_igi_fa_rssi(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+void rtw89_phy_cal_igi_fa_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, bool is_linked)
{
struct rtw89_dig_info *dig = &bb->dig;
u8 igi_min;
@@ -7569,6 +7673,8 @@ void rtw89_phy_cal_igi_fa_rssi(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb
} else {
dig->igi_fa_rssi = dig->dyn_igi_max;
}
+
+ rtw89_phy_dig_diag(rtwdev, bb, is_linked);
}
struct rtw89_phy_iter_mcc_dig {
@@ -7597,7 +7703,7 @@ static void rtw89_phy_set_mcc_dig(struct rtw89_dev *rtwdev,
}
chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
- rtw89_phy_cal_igi_fa_rssi(rtwdev, bb);
+ rtw89_phy_cal_igi_fa_rssi(rtwdev, bb, is_linked);
pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, dig->igi_fa_rssi,
is_linked, chan);
rtw89_fw_h2c_mcc_dig(rtwdev, rtwvif_link->chanctx_idx,
@@ -7742,7 +7848,7 @@ static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
}
dig->is_linked_pre = is_linked;
- rtw89_phy_cal_igi_fa_rssi(rtwdev, bb);
+ rtw89_phy_cal_igi_fa_rssi(rtwdev, bb, is_linked);
rtw89_debug(rtwdev, RTW89_DBG_DIG,
"rssi=%03d, dyn_joint(max,min)=(%d,%d), final_rssi=%d\n",
@@ -7997,6 +8103,14 @@ static void rtw89_phy_env_monitor_init(struct rtw89_dev *rtwdev)
__rtw89_phy_env_monitor_init(rtwdev, bb);
}
+static void rtw89_phy_diag_init(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_bb_ctx *bb;
+
+ rtw89_for_each_capab_bb(rtwdev, bb)
+ memset(&bb->diag, 0, sizeof(bb->diag));
+}
+
static void __rtw89_phy_edcca_init(struct rtw89_dev *rtwdev,
struct rtw89_bb_ctx *bb)
{
@@ -8037,6 +8151,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev)
rtw89_chip_bb_sethw(rtwdev);
+ rtw89_phy_diag_init(rtwdev);
rtw89_phy_env_monitor_init(rtwdev);
rtw89_phy_nhm_setting_init(rtwdev);
rtw89_physts_parsing_init(rtwdev);
@@ -8613,6 +8728,24 @@ void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb
edcca_regs->ppdu_mask, th, bb->phy_idx);
}
+static void rtw89_phy_edcca_diag(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+#define RTW89_DIAG_BB_EDCCA_RATIO_TH 50
+#define RTW89_DIAG_BB_EDCCA_TX_TH 10
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ struct rtw89_traffic_stats *stats = &rtwdev->stats;
+ struct rtw89_diag_bb *diag = &bb->diag;
+
+ diag->diag_bb_bitmap &= ~BIT(RTW89_DIAG_BB_EDCCA);
+
+ if (stats->tx_throughput <= RTW89_DIAG_BB_EDCCA_TX_TH ||
+ env->edcca_clm_ratio <= RTW89_DIAG_BB_EDCCA_RATIO_TH)
+ return;
+
+ diag->diag_bb_bitmap |= BIT(RTW89_DIAG_BB_EDCCA);
+ diag->diag_bb_cnt[RTW89_DIAG_BB_EDCCA]++;
+}
+
static
void __rtw89_phy_edcca_track(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
{
@@ -8620,6 +8753,7 @@ void __rtw89_phy_edcca_track(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
rtw89_phy_edcca_thre_calc(rtwdev, bb);
rtw89_phy_edcca_log(rtwdev, bb);
+ rtw89_phy_edcca_diag(rtwdev, bb);
}
void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev)
@@ -8770,6 +8904,10 @@ static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = {
.nhm_en_mask = B_NHM_EN_MSK,
.nhm_method = R_NHM_TH9,
.nhm_pwr_method_msk = B_NHM_PWDB_METHOD_MSK,
+ .edcca_clm_rdy = R_CLM_EDCCA_RDY,
+ .edcca_clm_rdy_mask = B_CLM_EDCCA_RDY,
+ .edcca_clm_cnt = R_CLM_EDCCA_RESULT,
+ .edcca_clm_cnt_mask = B_CLM_EDCCA_RESULT,
};
static const u32 rtw89_txinfo_reg_ax[] = {
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index 830cabefca39..a6e685654037 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -471,6 +471,10 @@ struct rtw89_ccx_regs {
u32 nhm_en_mask;
u32 nhm_method;
u32 nhm_pwr_method_msk;
+ u32 edcca_clm_rdy;
+ u32 edcca_clm_rdy_mask;
+ u32 edcca_clm_cnt;
+ u32 edcca_clm_cnt_mask;
};
struct rtw89_physts_regs {
diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c
index 9caddd19384c..5cd298a2c91b 100644
--- a/drivers/net/wireless/realtek/rtw89/phy_be.c
+++ b/drivers/net/wireless/realtek/rtw89/phy_be.c
@@ -74,6 +74,10 @@ static const struct rtw89_ccx_regs rtw89_ccx_regs_be = {
.nhm_en_mask = B_NHM_EN_MSK,
.nhm_method = R_NHM_TH9,
.nhm_pwr_method_msk = B_NHM_PWDB_METHOD_MSK,
+ .edcca_clm_rdy = R_CLM_EDCCA_RDY_V1,
+ .edcca_clm_rdy_mask = B_CLM_EDCCA_RDY,
+ .edcca_clm_cnt = R_CLM_EDCCA_RESULT_V1,
+ .edcca_clm_cnt_mask = B_CLM_EDCCA_RESULT,
};
static const struct rtw89_ccx_regs rtw89_ccx_regs_be_v1 = {
@@ -133,6 +137,10 @@ static const struct rtw89_ccx_regs rtw89_ccx_regs_be_v1 = {
.ifs_total_addr = R_IFS_TOTAL_BE4,
.ifs_cnt_done_mask = B_IFS_CNT_DONE_BE4,
.ifs_total_mask = B_IFS_TOTAL_BE4,
+ .edcca_clm_rdy = R_CLM_EDCCA_RDY_BE4,
+ .edcca_clm_rdy_mask = B_CLM_EDCCA_RDY,
+ .edcca_clm_cnt = R_CLM_EDCCA_RESULT_BE4,
+ .edcca_clm_cnt_mask = B_CLM_EDCCA_RESULT,
};
static const u32 rtw89_tx_info_reg_be[] = {
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index f5151e1ad58d..716747c3a10e 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -9146,6 +9146,14 @@
#define B_NHM_CNT11_MSK GENMASK(31, 16)
#define R_NHM_AX 0x1AA4
#define B_NHM_READY_MSK BIT(16)
+#define R_CLM_EDCCA_RESULT 0x1AC8
+#define R_CLM_EDCCA_RESULT_V1 0x0EC8
+#define R_CLM_EDCCA_RESULT_BE4 0x20EC8
+#define B_CLM_EDCCA_RESULT GENMASK(15, 0)
+#define R_CLM_EDCCA_RDY 0x1AC8
+#define R_CLM_EDCCA_RDY_V1 0x0EC8
+#define R_CLM_EDCCA_RDY_BE4 0x20EC8
+#define B_CLM_EDCCA_RDY BIT(16)
#define R_IFS_CLM_TX_CNT 0x1ACC
#define R_IFS_CLM_TX_CNT_V1 0x0ECC
#define R_IFS_CLM_TX_CNT_BE4 0x20ECC
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread