The queued and obsoleted scan events can be wrongly treated as events of
new scan request, causing unexpected scan result. Attach a software
sequence number to scan request and its corresponding events. When a new
scan request is acknowledged by firmware, purge the scan events if its
sequence number is not belong to current request.
Normal case:
mac80211 event work event BH
------------- ---------- --------
scan req #1 ---->o
|
<----o <...........................o
o
|
<--------------------------+
ieee80211_scan_completed()
Abnormal case (late event work):
mac80211 event work event BH
------------- ---------- --------
scan req #1 ---->o
|
<----o <...........................o
o #1
scan cancel #2 ->o
|
<----o <...........................o
o #2
| (patch to avoid this)
scan req #3 ---->o |
| |
<----o <..........|................o
| o #3
<--------------------------+
ieee80211_scan_completed()
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250715035259.45061-5-pkshih@realtek.com
bool connected;
bool abort;
u16 delay; /* in unit of ms */
+ u8 seq: 2;
};
enum rtw89_phy_bb_gain_band {
}
}
+void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
+ struct sk_buff *skb, *tmp;
+ int limit;
+
+ lockdep_assert_wiphy(rtwdev->hw->wiphy);
+
+ limit = skb_queue_len(&rtwdev->c2h_queue);
+
+ skb_queue_walk_safe(&rtwdev->c2h_queue, skb, tmp) {
+ struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb);
+
+ if (--limit < 0)
+ return;
+
+ if (!attr->is_scan_event || attr->scan_seq == scan_info->seq)
+ continue;
+
+ rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN,
+ "purge obsoleted scan event with seq=%d (cur=%d)\n",
+ attr->scan_seq, scan_info->seq);
+
+ skb_unlink(skb, &rtwdev->c2h_queue);
+ dev_kfree_skb_any(skb);
+ }
+}
+
static int rtw89_fw_write_h2c_reg(struct rtw89_dev *rtwdev,
struct rtw89_mac_h2c_info *info)
{
opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID;
}
- ret = mac->scan_offload(rtwdev, &opt, rtwvif_link, false);
+ ret = rtw89_mac_scan_offload(rtwdev, &opt, rtwvif_link, false);
+
out:
return ret;
}
u8 class;
u8 func;
u16 len;
+ u8 is_scan_event: 1;
+ u8 scan_seq: 2;
};
static inline struct rtw89_fw_c2h_attr *RTW89_SKB_C2H_CB(struct sk_buff *skb)
struct rtw89_sta_link *rtwsta_link);
void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h);
void rtw89_fw_c2h_work(struct wiphy *wiphy, struct wiphy_work *work);
+void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev);
int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct rtw89_sta_link *rtwsta_link,
{
/* N.B. This will run in interrupt context. */
struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait;
+ struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_wait_info *ps_wait = &rtwdev->mac.ps_wait;
const struct rtw89_c2h_done_ack *c2h =
(const struct rtw89_c2h_done_ack *)skb_c2h->data;
h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN;
break;
case H2C_FUNC_SCANOFLD:
+ scan_info->seq++;
cond = RTW89_SCANOFLD_WAIT_COND_START;
break;
case H2C_FUNC_SCANOFLD_BE:
+ scan_info->seq++;
cond = RTW89_SCANOFLD_BE_WAIT_COND_START;
h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN;
break;
const struct rtw89_c2h_scanofld *c2h =
(const struct rtw89_c2h_scanofld *)skb->data;
struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait;
+ struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
+ struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb);
struct rtw89_completion_data data = {};
unsigned int cond;
u8 status, reason;
+ attr->is_scan_event = 1;
+ attr->scan_seq = scan_info->seq;
+
status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS);
reason = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_RSN);
data.err = status != RTW89_SCAN_STATUS_SUCCESS;
#define __RTW89_MAC_H__
#include "core.h"
+#include "fw.h"
#include "reg.h"
#define MAC_MEM_DUMP_PAGE_SIZE_AX 0x40000
return mac->fwdl_secure_idmem_share_mode(rtwdev, mode);
}
+
+static inline
+int rtw89_mac_scan_offload(struct rtw89_dev *rtwdev,
+ struct rtw89_scan_option *option,
+ struct rtw89_vif_link *rtwvif_link,
+ bool wowlan)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ int ret;
+
+ ret = mac->scan_offload(rtwdev, option, rtwvif_link, wowlan);
+
+ if (option->enable) {
+ /*
+ * At this point, new scan request is acknowledged by firmware,
+ * so scan events of previous scan request become obsoleted.
+ * Purge the queued scan events to prevent interference to
+ * current new request.
+ */
+ rtw89_fw_c2h_purge_obsoleted_scan_events(rtwdev);
+ }
+
+ return ret;
+}
#endif
opt.opch_end = RTW89_CHAN_INVALID;
}
- mac->scan_offload(rtwdev, &opt, rtwvif_link, true);
+ rtw89_mac_scan_offload(rtwdev, &opt, rtwvif_link, true);
return 0;
}