* [PATCH rtw-next 0/7] wifi: rtw89: debug: introduce BB diagnosis
@ 2026-04-29 13:26 Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 1/7] wifi: rtw89: mlo: rearrange MLSR link decision flow Ping-Ke Shih
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-04-29 13:26 UTC (permalink / raw)
To: linux-wireless; +Cc: damon.chen
In order to debug in field, introduce a BB diagnosis to assist in debugging
in remote environment. Add many counters to monitor the environment states,
and end user can report the counters via debugfs if connection isn't good
or disconnection.
This function is in initial stage, so detection and precision are still
continue to improve.
Kuan-Chung Chen (7):
wifi: rtw89: mlo: rearrange MLSR link decision flow
wifi: rtw89: phy: support per PHY RX statistics
wifi: rtw89: debug: bb_info entry including TX rate count for WiFi 7
chips
wifi: rtw89: debug: add PMAC counter in bb_info
wifi: rtw89: debug: extend bb_info with TX status and PER
wifi: rtw89: debug: add RX statistics in bb_info
wifi: rtw89: debug: add BB diagnose
drivers/net/wireless/realtek/rtw89/core.c | 68 ++-
drivers/net/wireless/realtek/rtw89/core.h | 163 +++++-
drivers/net/wireless/realtek/rtw89/debug.c | 482 ++++++++++++++++--
drivers/net/wireless/realtek/rtw89/fw.c | 128 ++++-
drivers/net/wireless/realtek/rtw89/fw.h | 35 ++
drivers/net/wireless/realtek/rtw89/mac80211.c | 11 +-
drivers/net/wireless/realtek/rtw89/phy.c | 476 ++++++++++++++++-
drivers/net/wireless/realtek/rtw89/phy.h | 28 +
drivers/net/wireless/realtek/rtw89/phy_be.c | 54 ++
drivers/net/wireless/realtek/rtw89/reg.h | 164 ++++++
drivers/net/wireless/realtek/rtw89/rtw8851b.c | 49 ++
drivers/net/wireless/realtek/rtw89/rtw8852a.c | 54 +-
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 ++
drivers/net/wireless/realtek/rtw89/txrx.h | 2 +
18 files changed, 1887 insertions(+), 72 deletions(-)
base-commit: 83d38df6929118c3f996b9e3351c2d5014073d87
--
2.25.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [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
* [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
* 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
end of thread, other threads:[~2026-05-06 8:23 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-29 13:26 [PATCH rtw-next 0/7] wifi: rtw89: debug: introduce BB diagnosis Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 1/7] wifi: rtw89: mlo: rearrange MLSR link decision flow Ping-Ke Shih
2026-05-06 8:23 ` Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 2/7] wifi: rtw89: phy: support per PHY RX statistics Ping-Ke Shih
2026-04-29 13:26 ` [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 ` [PATCH rtw-next 4/7] wifi: rtw89: debug: add PMAC counter in bb_info Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 5/7] wifi: rtw89: debug: extend bb_info with TX status and PER Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 6/7] wifi: rtw89: debug: add RX statistics in bb_info Ping-Ke Shih
2026-04-29 13:26 ` [PATCH rtw-next 7/7] wifi: rtw89: debug: add BB diagnose Ping-Ke Shih
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox