]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: rtw89: extend HW scan of WiFi 7 chips for extra OP chan when concurrency
authorChih-Kang Chang <gary.chang@realtek.com>
Thu, 10 Jul 2025 04:24:14 +0000 (12:24 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Tue, 15 Jul 2025 01:28:22 +0000 (09:28 +0800)
HW scan of WiFi 7 chips supports multiple op channel configurations.
When concurrency, fill two channels info to HW scan to avoid packet
lost.

However, the OP chan timing is arranged by FW, and the actual stay
period depends on AP. It's hard to calculate total scan time for once
NoA in advance. Therefore, change the scan back to GO OP channel every
200TU and TX beacon to ensure GC doesn't beacon loss. Additionally, add
a period NoA with large duration to ensure GC doesn't TX packet during
GO scanning and can still listen beacon at TBTT to update the new NoA
info after scan complete.

Signed-off-by: Chih-Kang Chang <gary.chang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250710042423.73617-6-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/fw.h

index c003a31477bb0d3300b46b9299729d5db74ad09a..2faf0889f7dfa0681c3cbbf77a4eef325e381bba 100644 (file)
@@ -5539,7 +5539,9 @@ struct rtw89_early_h2c {
 struct rtw89_hw_scan_extra_op {
        bool set;
        u8 macid;
+       u8 port;
        struct rtw89_chan chan;
+       struct rtw89_vif_link *rtwvif_link;
 };
 
 struct rtw89_hw_scan_info {
index 1fd88dc7da85c00444d952aaa2dd3cc2b24bba29..20b7b4b15450c35c3189ed18bb3074b3fdaa727c 100644 (file)
@@ -5700,26 +5700,47 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
 {
        struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
        struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
+       const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op;
        struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
        struct cfg80211_scan_request *req = rtwvif->scan_req;
        struct rtw89_h2c_scanofld_be_macc_role *macc_role;
+       struct rtw89_hw_scan_extra_op scan_op[2] = {};
        struct rtw89_chan *op = &scan_info->op_chan;
        struct rtw89_h2c_scanofld_be_opch *opch;
        struct rtw89_pktofld_info *pkt_info;
        struct rtw89_h2c_scanofld_be *h2c;
+       struct ieee80211_vif *vif;
        struct sk_buff *skb;
        u8 macc_role_size = sizeof(*macc_role) * option->num_macc_role;
        u8 opch_size = sizeof(*opch) * option->num_opch;
+       enum rtw89_scan_be_opmode opmode;
        u8 probe_id[NUM_NL80211_BANDS];
        u8 scan_offload_ver = U8_MAX;
        u8 cfg_len = sizeof(*h2c);
        unsigned int cond;
+       u8 ap_idx = U8_MAX;
        u8 ver = U8_MAX;
+       u8 policy_val;
        void *ptr;
+       u8 txbcn;
        int ret;
        u32 len;
        u8 i;
 
+       scan_op[0].macid = rtwvif_link->mac_id;
+       scan_op[0].port = rtwvif_link->port;
+       scan_op[0].chan = *op;
+       vif = rtwvif_to_vif(rtwvif_link->rtwvif);
+       if (vif->type == NL80211_IFTYPE_AP)
+               ap_idx = 0;
+
+       if (ext->set) {
+               scan_op[1] = *ext;
+               vif = rtwvif_to_vif(ext->rtwvif_link->rtwvif);
+               if (vif->type == NL80211_IFTYPE_AP)
+                       ap_idx = 1;
+       }
+
        rtw89_scan_get_6g_disabled_chan(rtwdev, option);
 
        if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V0, &rtwdev->fw)) {
@@ -5822,29 +5843,35 @@ flex_member:
        }
 
        for (i = 0; i < option->num_opch; i++) {
+               bool is_ap_idx = i == ap_idx;
+
+               opmode = is_ap_idx ? RTW89_SCAN_OPMODE_TBTT : RTW89_SCAN_OPMODE_INTV;
+               policy_val = is_ap_idx ? 2 : RTW89_OFF_CHAN_TIME / 10;
+               txbcn = is_ap_idx ? 1 : 0;
+
                opch = ptr;
-               opch->w0 = le32_encode_bits(rtwvif_link->mac_id,
+               opch->w0 = le32_encode_bits(scan_op[i].macid,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W0_MACID) |
                           le32_encode_bits(option->band,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W0_BAND) |
-                          le32_encode_bits(rtwvif_link->port,
+                          le32_encode_bits(scan_op[i].port,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) |
-                          le32_encode_bits(RTW89_SCAN_OPMODE_INTV,
+                          le32_encode_bits(opmode,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) |
                           le32_encode_bits(true,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W0_TXNULL) |
-                          le32_encode_bits(RTW89_OFF_CHAN_TIME / 10,
+                          le32_encode_bits(policy_val,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY_VAL);
 
-               opch->w1 = le32_encode_bits(op->band_type,
+               opch->w1 = le32_encode_bits(scan_op[i].chan.band_type,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W1_CH_BAND) |
-                          le32_encode_bits(op->band_width,
+                          le32_encode_bits(scan_op[i].chan.band_width,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W1_BW) |
                           le32_encode_bits(0x3,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W1_NOTIFY) |
-                          le32_encode_bits(op->primary_channel,
+                          le32_encode_bits(scan_op[i].chan.primary_channel,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W1_PRI_CH) |
-                          le32_encode_bits(op->channel,
+                          le32_encode_bits(scan_op[i].chan.channel,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W1_CENTRAL_CH);
 
                opch->w2 = le32_encode_bits(0,
@@ -5852,7 +5879,9 @@ flex_member:
                           le32_encode_bits(0,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF) |
                           le32_encode_bits(rtw89_is_mlo_1_1(rtwdev) ? 1 : 2,
-                                           RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS);
+                                           RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS) |
+                          le32_encode_bits(txbcn,
+                                           RTW89_H2C_SCANOFLD_BE_OPCH_W2_TXBCN);
 
                opch->w3 = le32_encode_bits(RTW89_SCANOFLD_PKT_NONE,
                                            RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0) |
@@ -7625,7 +7654,7 @@ out:
 
 static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev,
                                                 struct rtw89_vif_link *rtwvif_link,
-                                                u16 tu)
+                                                u16 tu, bool scan)
 {
        struct ieee80211_p2p_noa_desc noa_desc = {};
        struct ieee80211_bss_conf *bss_conf;
@@ -7651,17 +7680,24 @@ static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev,
        }
 
        noa_desc.start_time = cpu_to_le32(tsf);
-       noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(tu));
-       noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(tu));
-       noa_desc.count = 1;
+       if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) {
+               noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(tu));
+               noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(tu));
+               noa_desc.count = 1;
+       } else {
+               noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(20000));
+               noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(20000));
+               noa_desc.count = 255;
+       }
 
        rtw89_p2p_noa_renew(rtwvif_link);
-       rtw89_p2p_noa_append(rtwvif_link, &noa_desc);
+       if (scan)
+               rtw89_p2p_noa_append(rtwvif_link, &noa_desc);
+
        rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link);
 }
 
-static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev,
-                                           const struct cfg80211_scan_request *req)
+static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, bool scan)
 {
        const struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt;
        const struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
@@ -7676,6 +7712,9 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev,
 
        lockdep_assert_wiphy(rtwdev->hw->wiphy);
 
+       if (!scan)
+               goto update;
+
        list_for_each_safe(pos, tmp, &scan_info->chan_list) {
                switch (chip->chip_gen) {
                case RTW89_CHIP_AX:
@@ -7699,6 +7738,7 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev,
                return;
        }
 
+update:
        list_for_each_entry(rtwvif, &mgnt->active_list, mgnt_entry) {
                unsigned int link_id;
 
@@ -7707,7 +7747,8 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev,
                        continue;
 
                rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
-                       rtw89_hw_scan_update_link_beacon_noa(rtwdev, rtwvif_link, tu);
+                       rtw89_hw_scan_update_link_beacon_noa(rtwdev, rtwvif_link,
+                                                            tu, scan);
        }
 }
 
@@ -7742,7 +7783,9 @@ static void rtw89_hw_scan_set_extra_op_info(struct rtw89_dev *rtwdev,
                *ext = (struct rtw89_hw_scan_extra_op){
                        .set = true,
                        .macid = tmp_link->mac_id,
+                       .port = tmp_link->port,
                        .chan = *tmp_chan,
+                       .rtwvif_link = tmp_link,
                };
 
                rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN,
@@ -7815,7 +7858,7 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
        rtw89_phy_dig_suspend(rtwdev);
 
        if (mode == RTW89_ENTITY_MODE_MCC)
-               rtw89_hw_scan_update_beacon_noa(rtwdev, req);
+               rtw89_hw_scan_update_beacon_noa(rtwdev, true);
 
        return 0;
 }
@@ -7828,6 +7871,7 @@ struct rtw89_hw_scan_complete_cb_data {
 static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data)
 {
        const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+       enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev);
        struct rtw89_hw_scan_complete_cb_data *cb_data = data;
        struct rtw89_vif_link *rtwvif_link = cb_data->rtwvif_link;
        struct cfg80211_scan_info info = {
@@ -7850,6 +7894,9 @@ static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data)
 
        rtw89_hw_scan_cleanup(rtwdev, rtwvif_link);
 
+       if (mode == RTW89_ENTITY_MODE_MCC)
+               rtw89_hw_scan_update_beacon_noa(rtwdev, false);
+
        return 0;
 }
 
@@ -7916,6 +7963,8 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev,
                          bool enable)
 {
        const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+       struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
+       const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op;
        struct rtw89_scan_option opt = {0};
        bool connected;
        int ret = 0;
@@ -7940,6 +7989,9 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev,
                opt.num_macc_role = 0;
                opt.mlo_mode = rtwdev->mlo_dbcc_mode;
                opt.num_opch = connected ? 1 : 0;
+               if (connected && ext->set)
+                       opt.num_opch++;
+
                opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID;
        }
 
index 22b2b2a716efc6368c535950246d901e10e4b29b..479a9f980b7f5c63029ce50b56f10a2042ab48b4 100644 (file)
@@ -2817,6 +2817,7 @@ struct rtw89_h2c_scanofld_be_opch {
 #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_PKTS_CTRL GENMASK(7, 0)
 #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF GENMASK(15, 8)
 #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS GENMASK(18, 16)
+#define RTW89_H2C_SCANOFLD_BE_OPCH_W2_TXBCN BIT(19)
 #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0 GENMASK(7, 0)
 #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT1 GENMASK(15, 8)
 #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT2 GENMASK(23, 16)