wifi: rtw89: mcc: deal with non-periodic NoA

Originally, MCC just took periodic NoA into account. When the connected GO
announces non-periodic NoA and GC side is during MCC, sometimes GC cannot
receive beacons well if the MCC scheduling conflicts with the non-periodic
NoA planning. After the loss exceeds the tolerable amount, beacon filter
will report connection loss. However, in this case, the loss is acceptable.
So now, MCC will calculate the range of non-periodic NoA. And then, don't
care beacon loss during the range.

Besides, rtw89_mcc_fill_role_limit() only makes sense for GC. Remove the
redundant check of GO.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250511035217.10410-6-pkshih@realtek.com
This commit is contained in:
Zong-Zhe Yang
2025-05-11 11:52:16 +08:00
committed by Ping-Ke Shih
parent eec9dfad1b
commit 122b74ac9b
8 changed files with 173 additions and 2 deletions

View File

@@ -776,9 +776,11 @@ static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev,
int ret;
int i;
if (!mcc_role->is_go && !mcc_role->is_gc)
if (!mcc_role->is_gc)
return;
rtw89_p2p_noa_once_recalc(rtwvif_link);
rcu_read_lock();
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);

View File

@@ -4004,6 +4004,9 @@ int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev,
if (vif->type == NL80211_IFTYPE_STATION)
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, false);
if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT)
rtw89_p2p_noa_once_deinit(rtwvif_link);
return 0;
}

View File

@@ -3485,6 +3485,14 @@ struct rtw89_p2p_noa_setter {
u8 noa_index;
};
struct rtw89_ps_noa_once_handler {
bool in_duration;
u64 tsf_begin;
u64 tsf_end;
struct wiphy_delayed_work set_work;
struct wiphy_delayed_work clr_work;
};
struct rtw89_vif_link {
struct rtw89_vif *rtwvif;
struct list_head dlink_schd;
@@ -3531,6 +3539,7 @@ struct rtw89_vif_link {
struct rtw89_phy_rate_pattern rate_pattern;
struct list_head general_pkt_list;
struct rtw89_p2p_noa_setter p2p_noa;
struct rtw89_ps_noa_once_handler noa_once;
};
enum rtw89_lv1_rcvy_step {

View File

@@ -5025,7 +5025,8 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l
switch (type) {
case RTW89_BCN_FLTR_BEACON_LOSS:
if (!rtwdev->scanning && !rtwvif->offchan)
if (!rtwdev->scanning && !rtwvif->offchan &&
!rtwvif_link->noa_once.in_duration)
ieee80211_connection_loss(vif);
else
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true);

View File

@@ -114,6 +114,8 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev,
wiphy_work_init(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work);
INIT_LIST_HEAD(&rtwvif_link->general_pkt_list);
rtw89_p2p_noa_once_init(rtwvif_link);
rtwvif_link->hit_rule = 0;
rtwvif_link->bcn_hit_cond = 0;
rtwvif_link->chanctx_assigned = false;
@@ -143,6 +145,8 @@ static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev,
wiphy_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->update_beacon_work);
rtw89_p2p_noa_once_deinit(rtwvif_link);
rtw89_leave_ps_mode(rtwdev);
rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, NULL, BTC_ROLE_STOP);

View File

@@ -382,3 +382,150 @@ u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data)
tail = ie->noa_desc + setter->noa_count;
return tail - *data;
}
static void rtw89_ps_noa_once_set_work(struct wiphy *wiphy, struct wiphy_work *work)
{
struct rtw89_ps_noa_once_handler *noa_once =
container_of(work, struct rtw89_ps_noa_once_handler, set_work.work);
lockdep_assert_wiphy(wiphy);
noa_once->in_duration = true;
}
static void rtw89_ps_noa_once_clr_work(struct wiphy *wiphy, struct wiphy_work *work)
{
struct rtw89_ps_noa_once_handler *noa_once =
container_of(work, struct rtw89_ps_noa_once_handler, clr_work.work);
struct rtw89_vif_link *rtwvif_link =
container_of(noa_once, struct rtw89_vif_link, noa_once);
struct rtw89_dev *rtwdev = rtwvif_link->rtwvif->rtwdev;
lockdep_assert_wiphy(wiphy);
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true);
noa_once->in_duration = false;
}
void rtw89_p2p_noa_once_init(struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_ps_noa_once_handler *noa_once = &rtwvif_link->noa_once;
noa_once->in_duration = false;
noa_once->tsf_begin = 0;
noa_once->tsf_end = 0;
wiphy_delayed_work_init(&noa_once->set_work, rtw89_ps_noa_once_set_work);
wiphy_delayed_work_init(&noa_once->clr_work, rtw89_ps_noa_once_clr_work);
}
static void rtw89_p2p_noa_once_cancel(struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_ps_noa_once_handler *noa_once = &rtwvif_link->noa_once;
struct rtw89_dev *rtwdev = rtwvif_link->rtwvif->rtwdev;
struct wiphy *wiphy = rtwdev->hw->wiphy;
wiphy_delayed_work_cancel(wiphy, &noa_once->set_work);
wiphy_delayed_work_cancel(wiphy, &noa_once->clr_work);
}
void rtw89_p2p_noa_once_deinit(struct rtw89_vif_link *rtwvif_link)
{
rtw89_p2p_noa_once_cancel(rtwvif_link);
rtw89_p2p_noa_once_init(rtwvif_link);
}
void rtw89_p2p_noa_once_recalc(struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_ps_noa_once_handler *noa_once = &rtwvif_link->noa_once;
struct rtw89_dev *rtwdev = rtwvif_link->rtwvif->rtwdev;
const struct ieee80211_p2p_noa_desc *noa_desc;
struct wiphy *wiphy = rtwdev->hw->wiphy;
struct ieee80211_bss_conf *bss_conf;
u64 tsf_begin = U64_MAX, tsf_end;
u64 set_delay_us = 0;
u64 clr_delay_us = 0;
u32 start_time;
u32 interval;
u32 duration;
u64 tsf;
int ret;
int i;
lockdep_assert_wiphy(wiphy);
ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf);
if (ret) {
rtw89_warn(rtwdev, "%s: failed to get tsf\n", __func__);
return;
}
rcu_read_lock();
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
for (i = 0; i < ARRAY_SIZE(bss_conf->p2p_noa_attr.desc); i++) {
bool first = tsf_begin == U64_MAX;
u64 tmp;
noa_desc = &bss_conf->p2p_noa_attr.desc[i];
if (noa_desc->count == 0 || noa_desc->count == 255)
continue;
start_time = le32_to_cpu(noa_desc->start_time);
interval = le32_to_cpu(noa_desc->interval);
duration = le32_to_cpu(noa_desc->duration);
if (unlikely(duration == 0 ||
(noa_desc->count > 1 && interval == 0)))
continue;
tmp = start_time + interval * (noa_desc->count - 1) + duration;
tmp = (tsf & GENMASK_ULL(63, 32)) + tmp;
if (unlikely(tmp <= tsf))
continue;
tsf_end = first ? tmp : max(tsf_end, tmp);
tmp = (tsf & GENMASK_ULL(63, 32)) | start_time;
tsf_begin = first ? tmp : min(tsf_begin, tmp);
}
rcu_read_unlock();
if (tsf_begin == U64_MAX)
return;
rtw89_p2p_noa_once_cancel(rtwvif_link);
if (noa_once->tsf_end > tsf) {
tsf_begin = min(tsf_begin, noa_once->tsf_begin);
tsf_end = max(tsf_end, noa_once->tsf_end);
}
clr_delay_us = min_t(u64, tsf_end - tsf, UINT_MAX);
if (tsf_begin <= tsf) {
noa_once->in_duration = true;
goto out;
}
set_delay_us = tsf_begin - tsf;
if (unlikely(set_delay_us > UINT_MAX)) {
rtw89_warn(rtwdev, "%s: unhandled begin\n", __func__);
set_delay_us = 0;
clr_delay_us = 0;
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true);
noa_once->in_duration = false;
}
out:
if (set_delay_us)
wiphy_delayed_work_queue(wiphy, &noa_once->set_work,
usecs_to_jiffies(set_delay_us));
if (clr_delay_us)
wiphy_delayed_work_queue(wiphy, &noa_once->clr_work,
usecs_to_jiffies(clr_delay_us));
noa_once->tsf_begin = tsf_begin;
noa_once->tsf_end = tsf_end;
}

View File

@@ -22,6 +22,9 @@ void rtw89_p2p_noa_renew(struct rtw89_vif_link *rtwvif_link);
void rtw89_p2p_noa_append(struct rtw89_vif_link *rtwvif_link,
const struct ieee80211_p2p_noa_desc *desc);
u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data);
void rtw89_p2p_noa_once_init(struct rtw89_vif_link *rtwvif_link);
void rtw89_p2p_noa_once_deinit(struct rtw89_vif_link *rtwvif_link);
void rtw89_p2p_noa_once_recalc(struct rtw89_vif_link *rtwvif_link);
static inline void rtw89_leave_ips_by_hwflags(struct rtw89_dev *rtwdev)
{

View File

@@ -310,6 +310,8 @@ static void ser_reset_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtwvif_link->net_type = RTW89_NET_TYPE_NO_LINK;
rtwvif_link->trigger = false;
rtwvif_link->rand_tsf_done = false;
rtw89_p2p_noa_once_deinit(rtwvif_link);
}
}