]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: rtw89: mcc: deal with non-periodic NoA
authorZong-Zhe Yang <kevin_yang@realtek.com>
Sun, 11 May 2025 03:52:16 +0000 (11:52 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Fri, 16 May 2025 00:43:41 +0000 (08:43 +0800)
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
drivers/net/wireless/realtek/rtw89/chan.c
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/mac.c
drivers/net/wireless/realtek/rtw89/mac80211.c
drivers/net/wireless/realtek/rtw89/ps.c
drivers/net/wireless/realtek/rtw89/ps.h
drivers/net/wireless/realtek/rtw89/ser.c

index 67acdcc1f535935cf9b5375691508c3dbffdf1ad..b7593c7465b96a0a4b5b12aefd78f346fa37ccd4 100644 (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);
index 3b2a2c6b9a440c19509452eb0be555ad321c3f3d..49447668cbf3d6305804766fd8bf1ee6c7cdfa01 100644 (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;
 }
 
index c0f2b62bc43b09342c71f81ff7b7a20de9cf8f96..1c8f3b9b7c4c661224634b6dfb43d3cbc02e7d5e 100644 (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 {
index e3976ba6dda253f7a02754d7c56776fdf440d472..9f0e30e7500927ae57fa13c6f72c87693e42d3ed 100644 (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);
index 22d13a0d5b8af6582018985975ba09b9b42cca95..a47971003bd422f3bc093c03b3e90ea6fed9a9e4 100644 (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);
index ac46a7baa00dbe8952e7ee62e45504c1d6d9b985..8e4fe73e7d775a153edb0f34d9054460d4b1ea8a 100644 (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;
+}
index 2b88f254a32d08774ebc9f4b06eb521994fdf143..b2c43d44820d3fd54c787a0c2b0f86c595f826cb 100644 (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)
 {
index 6ab25d71b05049b4e87749c7109a18e5132955ff..811c9148144117221fadf41857fda28fdf49cb43 100644 (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);
        }
 }