wifi: rtw89: refactor flow that hw scan handles channel list

FW has a limited amount of channels that can be dealt with by one HW scan
H2C command. Based on the limit, channels in scan request might be parsed
into SW structure piece by piece along with multiple HW scan H2C commands.
But, in order to estimate things of entire HW scan process, it's required
to have the whole parsed channel list when HW scan is going to start. So,
tweak HW scan flow to prepare the whole channel list ahead. Still, each HW
scan H2C command takes allowed amount of channels from the list according
to the limit.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250422014620.18421-5-pkshih@realtek.com
This commit is contained in:
Zong-Zhe Yang
2025-04-22 09:46:12 +08:00
committed by Ping-Ke Shih
parent 27982c9082
commit 57a5fbe39a
8 changed files with 179 additions and 57 deletions

View File

@@ -4873,6 +4873,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
continue;
INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]);
}
INIT_LIST_HEAD(&rtwdev->scan_info.chan_list);
INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work);
INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work);
INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work);
@@ -4958,9 +4959,6 @@ void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwv
struct rtw89_bb_ctx *bb = rtw89_get_bb_ctx(rtwdev, rtwvif_link->phy_idx);
rtwdev->scanning = true;
rtw89_leave_lps(rtwdev);
if (hw_scan)
rtw89_leave_ips_by_hwflags(rtwdev);
ether_addr_copy(rtwvif_link->mac_addr, mac_addr);
rtw89_btc_ntfy_scan_start(rtwdev, rtwvif_link->phy_idx, chan->band_type);

View File

@@ -5424,9 +5424,10 @@ struct rtw89_early_h2c {
struct rtw89_hw_scan_info {
struct rtw89_vif_link *scanning_vif;
struct list_head pkt_list[NUM_NL80211_BANDS];
struct list_head chan_list;
struct rtw89_chan op_chan;
bool connected;
bool abort;
u32 last_chan_idx;
};
enum rtw89_phy_bb_gain_band {

View File

@@ -15,6 +15,8 @@
#include "util.h"
#include "wow.h"
static bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev);
struct rtw89_eapol_2_of_2 {
u8 gtkbody[14];
u8 key_des_ver;
@@ -6535,7 +6537,7 @@ void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev)
rtw89_fw_prog_cnt_dump(rtwdev);
}
static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev)
static void rtw89_hw_scan_release_pkt_list(struct rtw89_dev *rtwdev)
{
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
struct rtw89_pktofld_info *info, *tmp;
@@ -6554,6 +6556,23 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev)
}
}
static void rtw89_hw_scan_cleanup(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
mac->free_chan_list(rtwdev);
rtw89_hw_scan_release_pkt_list(rtwdev);
rtwvif->scan_req = NULL;
rtwvif->scan_ies = NULL;
scan_info->scanning_vif = NULL;
scan_info->abort = false;
scan_info->connected = false;
}
static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev,
struct cfg80211_scan_request *req,
struct rtw89_pktofld_info *info,
@@ -6622,7 +6641,8 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
}
static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
struct rtw89_vif_link *rtwvif_link,
const u8 *mac_addr)
{
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
@@ -6631,7 +6651,7 @@ static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
int ret;
for (i = 0; i < num; i++) {
skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr,
skb = ieee80211_probereq_get(rtwdev->hw, mac_addr,
req->ssids[i].ssid,
req->ssids[i].ssid_len,
req->ie_len);
@@ -7005,24 +7025,24 @@ int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
return ret;
}
int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected)
int rtw89_hw_scan_prep_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_mac_chinfo_ax *ch_info, *tmp;
struct ieee80211_channel *channel;
struct list_head chan_list;
bool random_seq = req->flags & NL80211_SCAN_FLAG_RANDOM_SN;
int list_len, off_chan_time = 0;
enum rtw89_chan_type type;
int ret = 0;
int off_chan_time = 0;
int ret;
u32 idx;
INIT_LIST_HEAD(&chan_list);
for (idx = rtwdev->scan_info.last_chan_idx, list_len = 0;
idx < req->n_channels && list_len < RTW89_SCAN_LIST_LIMIT_AX;
idx++, list_len++) {
for (idx = 0; idx < req->n_channels; idx++) {
channel = req->channels[idx];
ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
if (!ch_info) {
@@ -7051,7 +7071,7 @@ int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
type = RTW89_CHAN_ACTIVE;
rtw89_hw_scan_add_chan_ax(rtwdev, type, req->n_ssids, ch_info);
if (connected &&
if (scan_info->connected &&
off_chan_time + ch_info->period > RTW89_OFF_CHAN_TIME) {
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) {
@@ -7066,13 +7086,13 @@ int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
rtw89_hw_scan_add_chan_ax(rtwdev, type, 0, tmp);
list_add_tail(&tmp->list, &chan_list);
off_chan_time = 0;
list_len++;
}
list_add_tail(&ch_info->list, &chan_list);
off_chan_time += ch_info->period;
}
rtwdev->scan_info.last_chan_idx = idx;
ret = rtw89_fw_h2c_scan_list_offload_ax(rtwdev, list_len, &chan_list);
list_splice_tail(&chan_list, &scan_info->chan_list);
return 0;
out:
list_for_each_entry_safe(ch_info, tmp, &chan_list, list) {
@@ -7083,6 +7103,46 @@ int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
return ret;
}
void rtw89_hw_scan_free_chan_list_ax(struct rtw89_dev *rtwdev)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_mac_chinfo_ax *ch_info, *tmp;
list_for_each_entry_safe(ch_info, tmp, &scan_info->chan_list, list) {
list_del(&ch_info->list);
kfree(ch_info);
}
}
int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_mac_chinfo_ax *ch_info, *tmp;
unsigned int list_len = 0;
struct list_head list;
int ret;
INIT_LIST_HEAD(&list);
list_for_each_entry_safe(ch_info, tmp, &scan_info->chan_list, list) {
list_move_tail(&ch_info->list, &list);
list_len++;
if (list_len == RTW89_SCAN_LIST_LIMIT_AX)
break;
}
ret = rtw89_fw_h2c_scan_list_offload_ax(rtwdev, list_len, &list);
list_for_each_entry_safe(ch_info, tmp, &list, list) {
list_del(&ch_info->list);
kfree(ch_info);
}
return ret;
}
int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
@@ -7136,25 +7196,24 @@ int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
return ret;
}
int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected)
int rtw89_hw_scan_prep_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_mac_chinfo_be *ch_info, *tmp;
struct ieee80211_channel *channel;
struct list_head chan_list;
enum rtw89_chan_type type;
int list_len, ret;
bool random_seq;
int ret;
u32 idx;
random_seq = !!(req->flags & NL80211_SCAN_FLAG_RANDOM_SN);
INIT_LIST_HEAD(&chan_list);
for (idx = rtwdev->scan_info.last_chan_idx, list_len = 0;
idx < req->n_channels && list_len < RTW89_SCAN_LIST_LIMIT_BE;
idx++, list_len++) {
for (idx = 0; idx < req->n_channels; idx++) {
channel = req->channels[idx];
ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
if (!ch_info) {
@@ -7184,9 +7243,8 @@ int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
list_add_tail(&ch_info->list, &chan_list);
}
rtwdev->scan_info.last_chan_idx = idx;
ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list,
rtwvif_link);
list_splice_tail(&chan_list, &scan_info->chan_list);
return 0;
out:
list_for_each_entry_safe(ch_info, tmp, &chan_list, list) {
@@ -7197,25 +7255,67 @@ int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
return ret;
}
void rtw89_hw_scan_free_chan_list_be(struct rtw89_dev *rtwdev)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_mac_chinfo_be *ch_info, *tmp;
list_for_each_entry_safe(ch_info, tmp, &scan_info->chan_list, list) {
list_del(&ch_info->list);
kfree(ch_info);
}
}
int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_mac_chinfo_be *ch_info, *tmp;
unsigned int list_len = 0;
struct list_head list;
int ret;
INIT_LIST_HEAD(&list);
list_for_each_entry_safe(ch_info, tmp, &scan_info->chan_list, list) {
list_move_tail(&ch_info->list, &list);
list_len++;
if (list_len == RTW89_SCAN_LIST_LIMIT_BE)
break;
}
ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &list,
rtwvif_link);
list_for_each_entry_safe(ch_info, tmp, &list, list) {
list_del(&ch_info->list);
kfree(ch_info);
}
return ret;
}
static int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected)
struct rtw89_vif_link *rtwvif_link,
const u8 *mac_addr)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
int ret;
ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif_link);
ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif_link, mac_addr);
if (ret) {
rtw89_err(rtwdev, "Update probe request failed\n");
goto out;
}
ret = mac->add_chan_list(rtwdev, rtwvif_link, connected);
ret = mac->prep_chan_list(rtwdev, rtwvif_link);
out:
return ret;
}
void rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct ieee80211_scan_request *scan_req)
int rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct ieee80211_scan_request *scan_req)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct cfg80211_scan_request *req = &scan_req->req;
@@ -7225,23 +7325,32 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
u32 rx_fltr = rtwdev->hal.rx_fltr;
u8 mac_addr[ETH_ALEN];
u32 reg;
int ret;
/* clone op and keep it during scan */
rtwdev->scan_info.op_chan = *chan;
rtwdev->scan_info.connected = rtw89_is_any_vif_connected_or_connecting(rtwdev);
rtwdev->scan_info.scanning_vif = rtwvif_link;
rtwdev->scan_info.last_chan_idx = 0;
rtwdev->scan_info.abort = false;
rtwvif->scan_ies = &scan_req->ies;
rtwvif->scan_req = req;
ieee80211_stop_queues(rtwdev->hw);
rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, false);
if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
get_random_mask_addr(mac_addr, req->mac_addr,
req->mac_addr_mask);
else
ether_addr_copy(mac_addr, rtwvif_link->mac_addr);
ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif_link, mac_addr);
if (ret) {
rtw89_hw_scan_cleanup(rtwdev, rtwvif_link);
return ret;
}
ieee80211_stop_queues(rtwdev->hw);
rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, false);
rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, true);
rx_fltr &= ~B_AX_A_BCN_CHK_EN;
@@ -7252,6 +7361,8 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rx_fltr);
rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_HW_SCAN);
return 0;
}
struct rtw89_hw_scan_complete_cb_data {
@@ -7262,20 +7373,16 @@ 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;
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
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 = {
.aborted = cb_data->aborted,
};
struct rtw89_vif *rtwvif;
u32 reg;
if (!rtwvif_link)
return -EINVAL;
rtwvif = rtwvif_link->rtwvif;
reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rtwdev->hal.rx_fltr);
@@ -7285,12 +7392,7 @@ static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data)
rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, true);
rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true);
rtw89_release_pkt_list(rtwdev);
rtwvif->scan_req = NULL;
rtwvif->scan_ies = NULL;
scan_info->last_chan_idx = 0;
scan_info->scanning_vif = NULL;
scan_info->abort = false;
rtw89_hw_scan_cleanup(rtwdev, rtwvif_link);
return 0;
}
@@ -7365,11 +7467,11 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev,
if (!rtwvif_link)
return -EINVAL;
connected = rtw89_is_any_vif_connected_or_connecting(rtwdev);
connected = rtwdev->scan_info.connected;
opt.enable = enable;
opt.target_ch_mode = connected;
if (enable) {
ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif_link, connected);
ret = mac->add_chan_list(rtwdev, rtwvif_link);
if (ret)
goto out;
}

View File

@@ -4716,9 +4716,9 @@ int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev,
struct rtw89_mac_c2h_info *c2h_info);
int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable);
void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev);
void rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct ieee80211_scan_request *scan_req);
int rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct ieee80211_scan_request *scan_req);
void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
bool aborted);
@@ -4727,12 +4727,18 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev,
bool enable);
void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
int rtw89_hw_scan_prep_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
void rtw89_hw_scan_free_chan_list_ax(struct rtw89_dev *rtwdev);
int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected);
struct rtw89_vif_link *rtwvif_link);
int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
int rtw89_hw_scan_prep_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
void rtw89_hw_scan_free_chan_list_be(struct rtw89_dev *rtwdev);
int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected);
struct rtw89_vif_link *rtwvif_link);
int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev);

View File

@@ -4899,11 +4899,11 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb,
struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif;
struct rtw89_vif *rtwvif;
struct rtw89_chan new;
u32 last_chan = rtwdev->scan_info.last_chan_idx, report_tsf;
u16 actual_period, expect_period;
u8 reason, status, tx_fail, band;
u8 mac_idx, sw_def, fw_def;
u8 ver = U8_MAX;
u32 report_tsf;
u16 chan;
int ret;
@@ -4962,7 +4962,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb,
return;
if (rtwvif_link && rtwvif->scan_req &&
last_chan < rtwvif->scan_req->n_channels) {
!list_empty(&rtwdev->scan_info.chan_list)) {
ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true);
if (ret) {
rtw89_hw_scan_abort(rtwdev, rtwvif_link);
@@ -6889,6 +6889,8 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
.is_txq_empty = mac_is_txq_empty_ax,
.prep_chan_list = rtw89_hw_scan_prep_chan_list_ax,
.free_chan_list = rtw89_hw_scan_free_chan_list_ax,
.add_chan_list = rtw89_hw_scan_add_chan_list_ax,
.add_chan_list_pno = rtw89_pno_scan_add_chan_list_ax,
.scan_offload = rtw89_fw_h2c_scan_offload_ax,

View File

@@ -1031,8 +1031,11 @@ struct rtw89_mac_gen_def {
bool (*is_txq_empty)(struct rtw89_dev *rtwdev);
int (*prep_chan_list)(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
void (*free_chan_list)(struct rtw89_dev *rtwdev);
int (*add_chan_list)(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected);
struct rtw89_vif_link *rtwvif_link);
int (*add_chan_list_pno)(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
int (*scan_offload)(struct rtw89_dev *rtwdev,

View File

@@ -1159,6 +1159,8 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw,
return;
}
rtw89_leave_lps(rtwdev);
rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, false);
}
@@ -1211,7 +1213,13 @@ static int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return -ENOLINK;
}
rtw89_hw_scan_start(rtwdev, rtwvif_link, req);
rtw89_leave_lps(rtwdev);
rtw89_leave_ips_by_hwflags(rtwdev);
ret = rtw89_hw_scan_start(rtwdev, rtwvif_link, req);
if (ret)
return ret;
ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true);
if (ret) {
rtw89_hw_scan_abort(rtwdev, rtwvif_link);

View File

@@ -2636,6 +2636,8 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = {
.is_txq_empty = mac_is_txq_empty_be,
.prep_chan_list = rtw89_hw_scan_prep_chan_list_be,
.free_chan_list = rtw89_hw_scan_free_chan_list_be,
.add_chan_list = rtw89_hw_scan_add_chan_list_be,
.add_chan_list_pno = rtw89_pno_scan_add_chan_list_be,
.scan_offload = rtw89_fw_h2c_scan_offload_be,