]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: rtw89: phy: support per PHY RX statistics
authorKuan-Chung Chen <damon.chen@realtek.com>
Wed, 29 Apr 2026 13:26:20 +0000 (21:26 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Wed, 6 May 2026 08:03:15 +0000 (16:03 +0800)
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>
Link: https://patch.msgid.link/20260429132625.1659182-3-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/debug.c
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/phy.c
drivers/net/wireless/realtek/rtw89/rtw8852a.c

index 03d80d012022a109d90b2dca112f57621f3714ac..81f3ae21dc18b4dfd329652f76ed535bc9aec307 100644 (file)
@@ -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;
 
index b290da650c7084ea7d80851effcc7968f8970831..f15a0c43ef6da46e7bf9c7e73fffc29c61767de3 100644 (file)
@@ -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;
index 2cb6e441b2f832374be17b64b285fbf08b279ecd..2d953bec149b8f99f30d393fbf5c845f23de145b 100644 (file)
@@ -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");
index b5d2540cf212505a0392c5e5534e467325451a9e..2a3662ed733f47219262bec909de24449b2d55ec 100644 (file)
@@ -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
index 95b5ace2a27e7898e68f5d51d4a186a21f91b756..29770cc5ea60a51c0e6598a3089f7fcfbaf6dc6e 100644 (file)
@@ -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,
index 9cd4c88ee57e3a01ab8fab9e73c13d9fb48d0521..b81eeb59be6016dee62a13bf359032924e570d5f 100644 (file)
@@ -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]);