wifi: rtw89: chan: support MCC on Wi-Fi 7 chips
authorZong-Zhe Yang <kevin_yang@realtek.com>
Tue, 13 Feb 2024 07:35:13 +0000 (15:35 +0800)
committerKalle Valo <kvalo@kernel.org>
Thu, 15 Feb 2024 11:09:48 +0000 (13:09 +0200)
On Wi-Fi 7 chips, concurrent stuffs are supported by FW MRC series
(multi-role concurrent) functions. And, driver has implemented the
corresponding SW handling in patches in front of this one. Now, we
extend SW MCC (multi-channel concurrent) flow to work on Wi-Fi 7
chips.

In SW point of view, things look as below.

|  SW  |                 |  FW func      |
|      |                 |  H2C/C2H      |
--------------------------------------------
|      |              ax                 |
|      |            /----|  FW MCC func  |
|  MCC | -- chip --+                     |
|      |            \----|  FW MRC func  |
|      |              be                 |

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://msgid.link/20240213073514.23796-5-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/chan.c
drivers/net/wireless/realtek/rtw89/core.h

index 7b9baf4..051a3ca 100644 (file)
@@ -322,6 +322,13 @@ static void rtw89_chanctx_notify(struct rtw89_dev *rtwdev,
        }
 }
 
+static bool rtw89_concurrent_via_mrc(struct rtw89_dev *rtwdev)
+{
+       enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
+
+       return chip_gen == RTW89_CHIP_BE;
+}
+
 /* This function centrally manages how MCC roles are sorted and iterated.
  * And, it guarantees that ordered_idx is less than NUM_OF_RTW89_MCC_ROLES.
  * So, if data needs to pass an array for ordered_idx, the array can declare
@@ -374,16 +381,13 @@ static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev,
        return remainder;
 }
 
-static u16 rtw89_mcc_get_bcn_ofst(struct rtw89_dev *rtwdev)
+static int __mcc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux)
 {
        struct rtw89_mcc_info *mcc = &rtwdev->mcc;
        struct rtw89_mcc_role *ref = &mcc->role_ref;
        struct rtw89_mcc_role *aux = &mcc->role_aux;
        struct rtw89_mac_mcc_tsf_rpt rpt = {};
        struct rtw89_fw_mcc_tsf_req req = {};
-       u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval);
-       u32 tbtt_ofst_ref, tbtt_ofst_aux;
-       u64 tsf_ref, tsf_aux;
        int ret;
 
        req.group = mcc->group;
@@ -393,11 +397,63 @@ static u16 rtw89_mcc_get_bcn_ofst(struct rtw89_dev *rtwdev)
        if (ret) {
                rtw89_debug(rtwdev, RTW89_DBG_CHAN,
                            "MCC h2c failed to request tsf: %d\n", ret);
-               return RTW89_MCC_DFLT_BCN_OFST_TIME;
+               return ret;
+       }
+
+       *tsf_ref = (u64)rpt.tsf_x_high << 32 | rpt.tsf_x_low;
+       *tsf_aux = (u64)rpt.tsf_y_high << 32 | rpt.tsf_y_low;
+
+       return 0;
+}
+
+static int __mrc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       struct rtw89_mcc_role *ref = &mcc->role_ref;
+       struct rtw89_mcc_role *aux = &mcc->role_aux;
+       struct rtw89_fw_mrc_req_tsf_arg arg = {};
+       struct rtw89_mac_mrc_tsf_rpt rpt = {};
+       int ret;
+
+       BUILD_BUG_ON(RTW89_MAC_MRC_MAX_REQ_TSF_NUM < NUM_OF_RTW89_MCC_ROLES);
+
+       arg.num = 2;
+       arg.infos[0].band = ref->rtwvif->mac_idx;
+       arg.infos[0].port = ref->rtwvif->port;
+       arg.infos[1].band = aux->rtwvif->mac_idx;
+       arg.infos[1].port = aux->rtwvif->port;
+
+       ret = rtw89_fw_h2c_mrc_req_tsf(rtwdev, &arg, &rpt);
+       if (ret) {
+               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                           "MRC h2c failed to request tsf: %d\n", ret);
+               return ret;
        }
 
-       tsf_ref = (u64)rpt.tsf_x_high << 32 | rpt.tsf_x_low;
-       tsf_aux = (u64)rpt.tsf_y_high << 32 | rpt.tsf_y_low;
+       *tsf_ref = rpt.tsfs[0];
+       *tsf_aux = rpt.tsfs[1];
+
+       return 0;
+}
+
+static u16 rtw89_mcc_get_bcn_ofst(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       struct rtw89_mcc_role *ref = &mcc->role_ref;
+       struct rtw89_mcc_role *aux = &mcc->role_aux;
+       u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval);
+       u32 tbtt_ofst_ref, tbtt_ofst_aux;
+       u64 tsf_ref, tsf_aux;
+       int ret;
+
+       if (rtw89_concurrent_via_mrc(rtwdev))
+               ret = __mrc_fw_req_tsf(rtwdev, &tsf_ref, &tsf_aux);
+       else
+               ret = __mcc_fw_req_tsf(rtwdev, &tsf_ref, &tsf_aux);
+
+       if (ret)
+               return RTW89_MCC_DFLT_BCN_OFST_TIME;
+
        tbtt_ofst_ref = rtw89_mcc_get_tbtt_ofst(rtwdev, ref, tsf_ref);
        tbtt_ofst_aux = rtw89_mcc_get_tbtt_ofst(rtwdev, aux, tsf_aux);
 
@@ -420,6 +476,28 @@ void rtw89_mcc_role_fw_macid_bitmap_set_bit(struct rtw89_mcc_role *mcc_role,
        mcc_role->macid_bitmap[idx] |= BIT(pos);
 }
 
+static
+u32 rtw89_mcc_role_fw_macid_bitmap_to_u32(struct rtw89_mcc_role *mcc_role)
+{
+       unsigned int macid;
+       unsigned int i, j;
+       u32 bitmap = 0;
+
+       for (i = 0; i < ARRAY_SIZE(mcc_role->macid_bitmap); i++) {
+               for (j = 0; j < 8; j++) {
+                       macid = i * 8 + j;
+                       if (macid >= 32)
+                               goto out;
+
+                       if (mcc_role->macid_bitmap[i] & BIT(j))
+                               bitmap |= BIT(macid);
+               }
+       }
+
+out:
+       return bitmap;
+}
+
 static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta)
 {
        struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
@@ -1181,7 +1259,11 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev,
        tsf_ofst_tgt = bcn_intvl_src_us - remainder;
 
        config->sync.macid_tgt = tgt->rtwvif->mac_id;
+       config->sync.band_tgt = tgt->rtwvif->mac_idx;
+       config->sync.port_tgt = tgt->rtwvif->port;
        config->sync.macid_src = src->rtwvif->mac_id;
+       config->sync.band_src = src->rtwvif->mac_idx;
+       config->sync.port_src = src->rtwvif->port;
        config->sync.offset = tsf_ofst_tgt / 1024;
        config->sync.enable = true;
 
@@ -1328,6 +1410,37 @@ static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ro
        return 0;
 }
 
+static
+void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role,
+                      struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       struct rtw89_mcc_role *ref = &mcc->role_ref;
+       struct rtw89_mcc_policy *policy = &role->policy;
+       struct rtw89_fw_mrc_add_slot_arg *slot_arg;
+       const struct rtw89_chan *chan;
+
+       slot_arg = &arg->slots[slot_idx];
+       role->slot_idx = slot_idx;
+
+       slot_arg->duration = role->duration;
+       slot_arg->role_num = 1;
+
+       chan = rtw89_chan_get(rtwdev, role->rtwvif->sub_entity_idx);
+
+       slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_WIFI;
+       slot_arg->roles[0].is_master = role == ref;
+       slot_arg->roles[0].band = chan->band_type;
+       slot_arg->roles[0].bw = chan->band_width;
+       slot_arg->roles[0].central_ch = chan->channel;
+       slot_arg->roles[0].primary_ch = chan->primary_channel;
+       slot_arg->roles[0].en_tx_null = !policy->dis_tx_null;
+       slot_arg->roles[0].null_early = policy->tx_null_early;
+       slot_arg->roles[0].macid = role->rtwvif->mac_id;
+       slot_arg->roles[0].macid_main_bitmap =
+               rtw89_mcc_role_fw_macid_bitmap_to_u32(role);
+}
+
 static int __mcc_fw_add_bt_role(struct rtw89_dev *rtwdev)
 {
        struct rtw89_mcc_info *mcc = &rtwdev->mcc;
@@ -1349,6 +1462,20 @@ static int __mcc_fw_add_bt_role(struct rtw89_dev *rtwdev)
        return 0;
 }
 
+static
+void __mrc_fw_add_bt_role(struct rtw89_dev *rtwdev,
+                         struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
+       struct rtw89_fw_mrc_add_slot_arg *slot_arg = &arg->slots[slot_idx];
+
+       slot_arg->duration = bt_role->duration;
+       slot_arg->role_num = 1;
+
+       slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_BT;
+}
+
 static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace)
 {
        struct rtw89_mcc_info *mcc = &rtwdev->mcc;
@@ -1434,6 +1561,130 @@ static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace)
        return 0;
 }
 
+static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev,
+                                 struct rtw89_fw_mrc_add_arg *arg)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       struct rtw89_mcc_role *ref = &mcc->role_ref;
+       struct rtw89_mcc_role *aux = &mcc->role_aux;
+       struct rtw89_mcc_config *config = &mcc->config;
+       struct rtw89_mcc_pattern *pattern = &config->pattern;
+       struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;
+       struct rtw89_fw_mrc_add_slot_arg *slot_arg_src;
+       u8 slot_idx_tgt;
+
+       if (!courtesy->enable)
+               return;
+
+       if (courtesy->macid_src == ref->rtwvif->mac_id) {
+               slot_arg_src = &arg->slots[ref->slot_idx];
+               slot_idx_tgt = aux->slot_idx;
+       } else {
+               slot_arg_src = &arg->slots[aux->slot_idx];
+               slot_idx_tgt = ref->slot_idx;
+       }
+
+       slot_arg_src->courtesy_target = slot_idx_tgt;
+       slot_arg_src->courtesy_period = courtesy->slot_num;
+       slot_arg_src->courtesy_en = true;
+}
+
+static int __mrc_fw_start(struct rtw89_dev *rtwdev, bool replace)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       struct rtw89_mcc_role *ref = &mcc->role_ref;
+       struct rtw89_mcc_role *aux = &mcc->role_aux;
+       struct rtw89_mcc_config *config = &mcc->config;
+       struct rtw89_mcc_pattern *pattern = &config->pattern;
+       struct rtw89_mcc_sync *sync = &config->sync;
+       struct rtw89_fw_mrc_start_arg start_arg = {};
+       struct rtw89_fw_mrc_add_arg add_arg = {};
+       int ret;
+
+       BUILD_BUG_ON(RTW89_MAC_MRC_MAX_ADD_SLOT_NUM <
+                    NUM_OF_RTW89_MCC_ROLES + 1 /* bt role */);
+
+       if (replace) {
+               start_arg.old_sch_idx = mcc->group;
+               start_arg.action = RTW89_H2C_MRC_START_ACTION_REPLACE_OLD;
+               mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group);
+       }
+
+       add_arg.sch_idx = mcc->group;
+       add_arg.sch_type = RTW89_H2C_MRC_SCH_BAND0_ONLY;
+
+       switch (pattern->plan) {
+       case RTW89_MCC_PLAN_TAIL_BT:
+               __mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
+               __mrc_fw_add_role(rtwdev, aux, &add_arg, 1);
+               __mrc_fw_add_bt_role(rtwdev, &add_arg, 2);
+
+               add_arg.slot_num = 3;
+               add_arg.btc_in_sch = true;
+               break;
+       case RTW89_MCC_PLAN_MID_BT:
+               __mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
+               __mrc_fw_add_bt_role(rtwdev, &add_arg, 1);
+               __mrc_fw_add_role(rtwdev, aux, &add_arg, 2);
+
+               add_arg.slot_num = 3;
+               add_arg.btc_in_sch = true;
+               break;
+       case RTW89_MCC_PLAN_NO_BT:
+               __mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
+               __mrc_fw_add_role(rtwdev, aux, &add_arg, 1);
+
+               add_arg.slot_num = 2;
+               add_arg.btc_in_sch = false;
+               break;
+       default:
+               rtw89_warn(rtwdev, "MCC unknown plan: %d\n", pattern->plan);
+               return -EFAULT;
+       }
+
+       __mrc_fw_add_courtesy(rtwdev, &add_arg);
+
+       ret = rtw89_fw_h2c_mrc_add(rtwdev, &add_arg);
+       if (ret) {
+               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                           "MRC h2c failed to trigger add: %d\n", ret);
+               return ret;
+       }
+
+       if (sync->enable) {
+               struct rtw89_fw_mrc_sync_arg sync_arg = {
+                       .offset = sync->offset,
+                       .src = {
+                               .band = sync->band_src,
+                               .port = sync->port_src,
+                       },
+                       .dest = {
+                               .band = sync->band_tgt,
+                               .port = sync->port_tgt,
+                       },
+               };
+
+               ret = rtw89_fw_h2c_mrc_sync(rtwdev, &sync_arg);
+               if (ret) {
+                       rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                                   "MRC h2c failed to trigger sync: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       start_arg.sch_idx = mcc->group;
+       start_arg.start_tsf = config->start_tsf;
+
+       ret = rtw89_fw_h2c_mrc_start(rtwdev, &start_arg);
+       if (ret) {
+               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                           "MRC h2c failed to trigger start: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed)
 {
        struct rtw89_mcc_info *mcc = &rtwdev->mcc;
@@ -1475,6 +1726,60 @@ static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_chang
        return 0;
 }
 
+static int __mrc_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_mrc_upd_duration_arg dur_arg = {
+               .sch_idx = mcc->group,
+               .start_tsf = config->start_tsf,
+               .slot_num = 2,
+               .slots[0] = {
+                       .slot_idx = ref->slot_idx,
+                       .duration = ref->duration,
+               },
+               .slots[1] = {
+                       .slot_idx = aux->slot_idx,
+                       .duration = aux->duration,
+               },
+       };
+       struct rtw89_fw_mrc_sync_arg sync_arg = {
+               .offset = sync->offset,
+               .src = {
+                       .band = sync->band_src,
+                       .port = sync->port_src,
+               },
+               .dest = {
+                       .band = sync->band_tgt,
+                       .port = sync->port_tgt,
+               },
+
+       };
+       int ret;
+
+       ret = rtw89_fw_h2c_mrc_upd_duration(rtwdev, &dur_arg);
+       if (ret) {
+               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                           "MRC h2c failed to update duration: %d\n", ret);
+               return ret;
+       }
+
+       if (!sync->enable || !sync_changed)
+               return 0;
+
+       ret = rtw89_fw_h2c_mrc_sync(rtwdev, &sync_arg);
+       if (ret) {
+               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                           "MRC h2c failed to trigger sync: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)
 {
        struct rtw89_mcc_info *mcc = &rtwdev->mcc;
@@ -1593,7 +1898,11 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
        if (ret)
                return ret;
 
-       ret = __mcc_fw_start(rtwdev, false);
+       if (rtw89_concurrent_via_mrc(rtwdev))
+               ret = __mrc_fw_start(rtwdev, false);
+       else
+               ret = __mcc_fw_start(rtwdev, false);
+
        if (ret)
                return ret;
 
@@ -1611,16 +1920,23 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev)
 
        rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC stop\n");
 
-       ret = rtw89_fw_h2c_stop_mcc(rtwdev, mcc->group,
-                                   ref->rtwvif->mac_id, true);
-       if (ret)
-               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
-                           "MCC h2c failed to trigger stop: %d\n", ret);
+       if (rtw89_concurrent_via_mrc(rtwdev)) {
+               ret = rtw89_fw_h2c_mrc_del(rtwdev, mcc->group);
+               if (ret)
+                       rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                                   "MRC h2c failed to trigger del: %d\n", ret);
+       } else {
+               ret = rtw89_fw_h2c_stop_mcc(rtwdev, mcc->group,
+                                           ref->rtwvif->mac_id, true);
+               if (ret)
+                       rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                                   "MCC h2c failed to trigger stop: %d\n", ret);
 
-       ret = rtw89_fw_h2c_del_mcc_group(rtwdev, mcc->group, true);
-       if (ret)
-               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
-                           "MCC h2c failed to delete group: %d\n", ret);
+               ret = rtw89_fw_h2c_del_mcc_group(rtwdev, mcc->group, true);
+               if (ret)
+                       rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                                   "MCC h2c failed to delete group: %d\n", ret);
+       }
 
        rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP);
 
@@ -1646,7 +1962,11 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev)
 
        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 (rtw89_concurrent_via_mrc(rtwdev))
+                       ret = __mrc_fw_start(rtwdev, true);
+               else
+                       ret = __mcc_fw_start(rtwdev, true);
+
                if (ret)
                        return ret;
        } else {
@@ -1655,7 +1975,11 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev)
                else
                        sync_changed = true;
 
-               ret = __mcc_fw_set_duration_no_bt(rtwdev, sync_changed);
+               if (rtw89_concurrent_via_mrc(rtwdev))
+                       ret = __mrc_fw_set_duration_no_bt(rtwdev, sync_changed);
+               else
+                       ret = __mcc_fw_set_duration_no_bt(rtwdev, sync_changed);
+
                if (ret)
                        return ret;
        }
@@ -1697,12 +2021,75 @@ static void rtw89_mcc_track(struct rtw89_dev *rtwdev)
        rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_BCN_OFFSET_CHANGE);
 }
 
+static int __mcc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
+                                    struct rtw89_mcc_role *upd)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       int ret;
+
+       ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group,
+                                           upd->rtwvif->mac_id,
+                                           upd->macid_bitmap);
+       if (ret) {
+               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                           "MCC h2c failed to update macid bitmap: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __mrc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
+                                    struct rtw89_mcc_role *cur,
+                                    struct rtw89_mcc_role *upd)
+{
+       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+       struct rtw89_fw_mrc_upd_bitmap_arg arg = {};
+       u32 old = rtw89_mcc_role_fw_macid_bitmap_to_u32(cur);
+       u32 new = rtw89_mcc_role_fw_macid_bitmap_to_u32(upd);
+       u32 add = new & ~old;
+       u32 del = old & ~new;
+       int ret;
+       int i;
+
+       arg.sch_idx = mcc->group;
+       arg.macid = upd->rtwvif->mac_id;
+
+       for (i = 0; i < 32; i++) {
+               if (add & BIT(i)) {
+                       arg.client_macid = i;
+                       arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_ADD;
+
+                       ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, &arg);
+                       if (ret)
+                               goto err;
+               }
+       }
+
+       for (i = 0; i < 32; i++) {
+               if (del & BIT(i)) {
+                       arg.client_macid = i;
+                       arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_DEL;
+
+                       ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, &arg);
+                       if (ret)
+                               goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+                   "MRC h2c failed to update bitmap: %d\n", ret);
+       return ret;
+}
+
 static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev,
                                      struct rtw89_mcc_role *mcc_role,
                                      unsigned int ordered_idx,
                                      void *data)
 {
-       struct rtw89_mcc_info *mcc = &rtwdev->mcc;
        struct rtw89_mcc_role upd = {
                .rtwvif = mcc_role->rtwvif,
        };
@@ -1716,14 +2103,13 @@ static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev,
                   sizeof(mcc_role->macid_bitmap)) == 0)
                return 0;
 
-       ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group,
-                                           upd.rtwvif->mac_id,
-                                           upd.macid_bitmap);
-       if (ret) {
-               rtw89_debug(rtwdev, RTW89_DBG_CHAN,
-                           "MCC h2c failed to update macid bitmap: %d\n", ret);
+       if (rtw89_concurrent_via_mrc(rtwdev))
+               ret = __mrc_fw_upd_macid_bitmap(rtwdev, mcc_role, &upd);
+       else
+               ret = __mcc_fw_upd_macid_bitmap(rtwdev, &upd);
+
+       if (ret)
                return ret;
-       }
 
        memcpy(mcc_role->macid_bitmap, upd.macid_bitmap,
               sizeof(mcc_role->macid_bitmap));
index 6269ae2..d62d230 100644 (file)
@@ -4868,6 +4868,9 @@ struct rtw89_mcc_role {
        struct rtw89_mcc_policy policy;
        struct rtw89_mcc_limit limit;
 
+       /* only valid when running with FW MRC mechanism */
+       u8 slot_idx;
+
        /* byte-array in LE order for FW */
        u8 macid_bitmap[BITS_TO_BYTES(RTW89_MAX_MAC_ID_NUM)];
 
@@ -4911,7 +4914,11 @@ struct rtw89_mcc_sync {
        bool enable;
        u16 offset; /* TU */
        u8 macid_src;
+       u8 band_src;
+       u8 port_src;
        u8 macid_tgt;
+       u8 band_tgt;
+       u8 port_tgt;
 };
 
 struct rtw89_mcc_config {