wifi: rtw89: mcc: track beacon offset and update when needed
authorZong-Zhe Yang <kevin_yang@realtek.com>
Fri, 8 Sep 2023 03:11:42 +0000 (11:11 +0800)
committerKalle Valo <kvalo@kernel.org>
Mon, 18 Sep 2023 14:28:45 +0000 (17:28 +0300)
In MCC STA+GC mode, the offset between TBTTs of remote AP and remote GO
might change. If the change is larger than tolerance, we should update
MCC after re-calculating parameters for new things. So, we track that in
rtw89_track_work() now. And, we add MCC update flow to tell FW either to
change durations of roles or to replace entire pattern according to how
MCC plans BT slot.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20230908031145.20931-6-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/chan.c
drivers/net/wireless/realtek/rtw89/chan.h
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.h

index 5ac6d60dfd73b872d663a8592bc3fcf90ad362e4..417fb5e98813fbfe6d2b8592c3f36bcfdac0e6ab 100644 (file)
@@ -1297,7 +1297,7 @@ static int __mcc_fw_add_bt_role(struct rtw89_dev *rtwdev)
        return 0;
 }
 
-static int __mcc_fw_start(struct rtw89_dev *rtwdev)
+static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace)
 {
        struct rtw89_mcc_info *mcc = &rtwdev->mcc;
        struct rtw89_mcc_role *ref = &mcc->role_ref;
@@ -1308,6 +1308,12 @@ static int __mcc_fw_start(struct rtw89_dev *rtwdev)
        struct rtw89_fw_mcc_start_req req = {};
        int ret;
 
+       if (replace) {
+               req.old_group = mcc->group;
+               req.old_group_action = RTW89_FW_MCC_OLD_GROUP_ACT_REPLACE;
+               mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group);
+       }
+
        req.group = mcc->group;
 
        switch (pattern->plan) {
@@ -1376,6 +1382,47 @@ static int __mcc_fw_start(struct rtw89_dev *rtwdev)
        return 0;
 }
 
+static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       struct rtw89_mcc_config *config = &mcc->config;
+       struct rtw89_mcc_sync *sync = &config->sync;
+       struct rtw89_mcc_role *ref = &mcc->role_ref;
+       struct rtw89_mcc_role *aux = &mcc->role_aux;
+       struct rtw89_fw_mcc_duration req = {
+               .group = mcc->group,
+               .btc_in_group = false,
+               .start_macid = ref->rtwvif->mac_id,
+               .macid_x = ref->rtwvif->mac_id,
+               .macid_y = aux->rtwvif->mac_id,
+               .duration_x = ref->duration,
+               .duration_y = aux->duration,
+               .start_tsf_high = config->start_tsf >> 32,
+               .start_tsf_low = config->start_tsf,
+       };
+       int ret;
+
+       ret = rtw89_fw_h2c_mcc_set_duration(rtwdev, &req);
+       if (ret) {
+               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                           "MCC h2c failed to set duration: %d\n", ret);
+               return ret;
+       }
+
+       if (!sync->enable || !sync_changed)
+               return 0;
+
+       ret = rtw89_fw_h2c_mcc_sync(rtwdev, mcc->group, sync->macid_src,
+                                   sync->macid_tgt, sync->offset);
+       if (ret) {
+               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                           "MCC h2c failed to trigger sync: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
 {
        struct rtw89_mcc_info *mcc = &rtwdev->mcc;
@@ -1407,7 +1454,7 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
        if (ret)
                return ret;
 
-       ret = __mcc_fw_start(rtwdev);
+       ret = __mcc_fw_start(rtwdev, false);
        if (ret)
                return ret;
 
@@ -1437,6 +1484,75 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev)
        rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP);
 }
 
+static int rtw89_mcc_update(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       struct rtw89_mcc_config *config = &mcc->config;
+       struct rtw89_mcc_config old_cfg = *config;
+       bool sync_changed;
+       int ret;
+
+       if (rtwdev->scanning)
+               rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
+
+       rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC update\n");
+
+       ret = rtw89_mcc_fill_config(rtwdev);
+       if (ret)
+               return ret;
+
+       if (old_cfg.pattern.plan != RTW89_MCC_PLAN_NO_BT ||
+           config->pattern.plan != RTW89_MCC_PLAN_NO_BT) {
+               ret = __mcc_fw_start(rtwdev, true);
+               if (ret)
+                       return ret;
+       } else {
+               if (memcmp(&old_cfg.sync, &config->sync, sizeof(old_cfg.sync)) == 0)
+                       sync_changed = false;
+               else
+                       sync_changed = true;
+
+               ret = __mcc_fw_set_duration_no_bt(rtwdev, sync_changed);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void rtw89_mcc_track(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       struct rtw89_mcc_config *config = &mcc->config;
+       struct rtw89_mcc_pattern *pattern = &config->pattern;
+       s16 tolerance;
+       u16 bcn_ofst;
+       u16 diff;
+
+       if (mcc->mode != RTW89_MCC_MODE_GC_STA)
+               return;
+
+       bcn_ofst = rtw89_mcc_get_bcn_ofst(rtwdev);
+       if (bcn_ofst > config->beacon_offset) {
+               diff = bcn_ofst - config->beacon_offset;
+               if (pattern->tob_aux < 0)
+                       tolerance = -pattern->tob_aux;
+               else
+                       tolerance = pattern->toa_aux;
+       } else {
+               diff = config->beacon_offset - bcn_ofst;
+               if (pattern->toa_aux < 0)
+                       tolerance = -pattern->toa_aux;
+               else
+                       tolerance = pattern->tob_aux;
+       }
+
+       if (diff <= tolerance)
+               return;
+
+       rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_BCN_OFFSET_CHANGE);
+}
+
 static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev,
                                      struct rtw89_mcc_role *mcc_role,
                                      unsigned int ordered_idx,
@@ -1485,6 +1601,7 @@ void rtw89_chanctx_work(struct work_struct *work)
        struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
                                                chanctx_work.work);
        struct rtw89_hal *hal = &rtwdev->hal;
+       bool update_mcc_pattern = false;
        enum rtw89_entity_mode mode;
        u32 changed = 0;
        int ret;
@@ -1508,8 +1625,16 @@ void rtw89_chanctx_work(struct work_struct *work)
                        rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
                break;
        case RTW89_ENTITY_MODE_MCC:
+               if (changed & BIT(RTW89_CHANCTX_BCN_OFFSET_CHANGE))
+                       update_mcc_pattern = true;
                if (changed & BIT(RTW89_CHANCTX_REMOTE_STA_CHANGE))
                        rtw89_mcc_update_macid_bitmap(rtwdev);
+               if (update_mcc_pattern) {
+                       ret = rtw89_mcc_update(rtwdev);
+                       if (ret)
+                               rtw89_warn(rtwdev, "failed to update MCC: %d\n",
+                                          ret);
+               }
                break;
        default:
                break;
@@ -1555,6 +1680,22 @@ void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev)
        rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_CHANGE_DFLT);
 }
 
+void rtw89_chanctx_track(struct rtw89_dev *rtwdev)
+{
+       enum rtw89_entity_mode mode;
+
+       lockdep_assert_held(&rtwdev->mutex);
+
+       mode = rtw89_get_entity_mode(rtwdev);
+       switch (mode) {
+       case RTW89_ENTITY_MODE_MCC:
+               rtw89_mcc_track(rtwdev);
+               break;
+       default:
+               break;
+       }
+}
+
 int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
                          struct ieee80211_chanctx_conf *ctx)
 {
index 2fca703c99f0d4de780026f24c935f4e0f833427..9fd46f5c37b9106847d0d3654818c707164a8b6c 100644 (file)
@@ -26,6 +26,8 @@
        (RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME)
 
 #define RTW89_MCC_DFLT_GROUP 0
+#define RTW89_MCC_NEXT_GROUP(cur) (((cur) + 1) % 4)
+
 #define RTW89_MCC_DFLT_TX_NULL_EARLY 3
 #define RTW89_MCC_DFLT_COURTESY_SLOT 3
 
@@ -78,6 +80,7 @@ void rtw89_chanctx_work(struct work_struct *work);
 void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev);
 void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev,
                                enum rtw89_chanctx_changes change);
+void rtw89_chanctx_track(struct rtw89_dev *rtwdev);
 int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
                          struct ieee80211_chanctx_conf *ctx);
 void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
index 68ffd753f4a0466a44d78c0e0ff0950e57a47fc2..b4f944ff52ec5d8679004ce5a6830f65f50ccbaf 100644 (file)
@@ -2722,6 +2722,7 @@ static void rtw89_track_work(struct work_struct *work)
        rtw89_phy_antdiv_track(rtwdev);
        rtw89_phy_ul_tb_ctrl_track(rtwdev);
        rtw89_tas_track(rtwdev);
+       rtw89_chanctx_track(rtwdev);
 
        if (rtwdev->lps_enabled && !rtwdev->btc.lps)
                rtw89_enter_lps_track(rtwdev);
index eb185b3ffa3cf6c3b52675a2bb1646122ff605f8..82291d9599a504298382ca47880dc85c3b44c686 100644 (file)
@@ -3789,6 +3789,7 @@ struct rtw89_chanctx_cfg {
 
 enum rtw89_chanctx_changes {
        RTW89_CHANCTX_REMOTE_STA_CHANGE,
+       RTW89_CHANCTX_BCN_OFFSET_CHANGE,
 
        NUM_OF_RTW89_CHANCTX_CHANGES,
        RTW89_CHANCTX_CHANGE_DFLT = NUM_OF_RTW89_CHANCTX_CHANGES,
index b034e4caed915d6d762d141538f841dad835b6e0..f965e24234471bfe22d294fd33c32f3b4f083465 100644 (file)
@@ -2931,6 +2931,11 @@ static inline void RTW89_SET_FWCMD_ADD_MCC_COURTESY_TARGET(void *cmd, u32 val)
        le32p_replace_bits((__le32 *)cmd + 3, val, GENMASK(23, 16));
 }
 
+enum rtw89_fw_mcc_old_group_actions {
+       RTW89_FW_MCC_OLD_GROUP_ACT_NONE = 0,
+       RTW89_FW_MCC_OLD_GROUP_ACT_REPLACE = 1,
+};
+
 struct rtw89_fw_mcc_start_req {
        u32 group: 2;
        u32 btc_in_group: 1;