@@ -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)
{
@@ -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,
@@ -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);
@@ -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,
@@ -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;