*     is &enum iwl_mac_beacon_flags.
  * @short_ssid: Short SSID
  * @reserved: reserved
- * @template_id: currently equal to the mac context id of the coresponding mac.
+ * @link_id: the firmware id of the link that will use this beacon
  * @tim_idx: the offset of the tim IE in the beacon
  * @tim_size: the length of the tim IE
  * @ecsa_offset: offset to the ECSA IE if present
        __le16 flags;
        __le32 short_ssid;
        __le32 reserved;
-       __le32 template_id;
+       __le32 link_id;
        __le32 tim_idx;
        __le32 tim_size;
        __le32 ecsa_offset;
        __le32 csa_offset;
        struct ieee80211_hdr frame[];
 } __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_10,
-              BEACON_TEMPLATE_CMD_API_S_VER_11,
-              BEACON_TEMPLATE_CMD_API_S_VER_12 */
+            * BEACON_TEMPLATE_CMD_API_S_VER_11,
+            * BEACON_TEMPLATE_CMD_API_S_VER_12,
+            * BEACON_TEMPLATE_CMD_API_S_VER_13
+            */
 
 struct iwl_beacon_notif {
        struct iwl_mvm_tx_resp beacon_notify_hdr;
 
        struct sk_buff *beacon;
        struct ieee80211_tx_info *info;
        struct iwl_mac_beacon_cmd beacon_cmd = {};
+       unsigned int link_id;
        u8 rate;
        int i;
 
        info = IEEE80211_SKB_CB(beacon);
        rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif);
 
-       beacon_cmd.flags =
-               cpu_to_le16(iwl_mvm_mac_ctxt_get_beacon_flags(mvm->fw, rate));
-       beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len);
-       beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
+       for_each_mvm_vif_valid_link(mvmvif, link_id) {
+               beacon_cmd.flags =
+                       cpu_to_le16(iwl_mvm_mac_ctxt_get_beacon_flags(mvm->fw,
+                                                                     rate));
+               beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len);
+               beacon_cmd.link_id = cpu_to_le32((u32)mvmvif->id);
 
-       iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx,
-                                &beacon_cmd.tim_size,
-                                beacon->data, beacon->len);
+               iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx,
+                                        &beacon_cmd.tim_size,
+                                        beacon->data, beacon->len);
 
-       iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd,
-                                        sizeof(beacon_cmd));
+               iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd,
+                                                sizeof(beacon_cmd));
+       }
        mutex_unlock(&mvm->mutex);
 
        dev_kfree_skb(beacon);
 
 
 static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
                                           struct ieee80211_vif *vif,
-                                          struct sk_buff *beacon)
+                                          struct sk_buff *beacon,
+                                          struct ieee80211_bss_conf *link_conf)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(beacon);
 
        /* Enable FILS on PSC channels only */
        rcu_read_lock();
-       ctx = rcu_dereference(vif->bss_conf.chanctx_conf);
+       ctx = rcu_dereference(link_conf->chanctx_conf);
        channel = ieee80211_frequency_to_channel(ctx->def.chan->center_freq);
        WARN_ON(channel == 0);
        if (cfg80211_channel_is_psc(ctx->def.chan) &&
 
        beacon_cmd.flags = cpu_to_le16(flags);
        beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len);
-       beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
+       beacon_cmd.link_id = cpu_to_le32((u32)mvmvif->id);
 
        if (vif->type == NL80211_IFTYPE_AP)
                iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx,
 
 int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
                                 struct ieee80211_vif *vif,
-                                struct sk_buff *beacon)
+                                struct sk_buff *beacon,
+                                struct ieee80211_bss_conf *link_conf)
 {
        if (WARN_ON(!beacon))
                return -EINVAL;
 
        if (fw_has_api(&mvm->fw->ucode_capa,
                       IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE))
-               return iwl_mvm_mac_ctxt_send_beacon_v9(mvm, vif, beacon);
+               return iwl_mvm_mac_ctxt_send_beacon_v9(mvm, vif, beacon,
+                                                      link_conf);
 
        return iwl_mvm_mac_ctxt_send_beacon_v7(mvm, vif, beacon);
 }
 
 /* The beacon template for the AP/GO/IBSS has changed and needs update */
 int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
-                                   struct ieee80211_vif *vif)
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_bss_conf *link_conf)
 {
        struct sk_buff *beacon;
        int ret;
        WARN_ON(vif->type != NL80211_IFTYPE_AP &&
                vif->type != NL80211_IFTYPE_ADHOC);
 
-       beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL, 0);
+       beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL,
+                                              link_conf->link_id);
        if (!beacon)
                return -ENOMEM;
 
        }
 #endif
 
-       ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon);
+       ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon, link_conf);
        dev_kfree_skb(beacon);
        return ret;
 }
        if (!ieee80211_beacon_cntdwn_is_complete(csa_vif)) {
                int c = ieee80211_beacon_update_cntdwn(csa_vif);
 
-               iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif);
+               iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif,
+                                               &csa_vif->bss_conf);
                if (csa_vif->p2p &&
                    !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2 &&
                    tx_success) {
 
 
        mutex_lock(&mvm->mutex);
 
-       /* Send the beacon template */
-       ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif);
-       if (ret)
-               goto out_unlock;
-
        /*
         * Re-calculate the tsf id, as the leader-follower relations depend on
         * the beacon interval, which was not known when the AP interface
        if (vif->type == NL80211_IFTYPE_AP)
                iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
 
-       /* Add the mac context */
-       ret = iwl_mvm_mac_ctxt_add(mvm, vif);
-       if (ret)
-               goto out_unlock;
+       /* For older devices need to send beacon template before adding mac
+        * context. For the newer, the beacon is a resource that belongs to a
+        * MAC, so need to send beacon template after adding the mac.
+        */
+       if (mvm->trans->trans_cfg->device_family > IWL_DEVICE_FAMILY_22000) {
+               /* Add the mac context */
+               ret = iwl_mvm_mac_ctxt_add(mvm, vif);
+               if (ret)
+                       goto out_unlock;
+
+               /* Send the beacon template */
+               ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf);
+               if (ret)
+                       goto out_unlock;
+       } else {
+               /* Send the beacon template */
+               ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf);
+               if (ret)
+                       goto out_unlock;
+
+               /* Add the mac context */
+               ret = iwl_mvm_mac_ctxt_add(mvm, vif);
+               if (ret)
+                       goto out_unlock;
+       }
 
        /* Perform the binding */
        ret = iwl_mvm_binding_add_vif(mvm, vif);
 
        /* Need to send a new beacon template to the FW */
        if (changes & BSS_CHANGED_BEACON &&
-           iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
+           iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, &vif->bss_conf))
                IWL_WARN(mvm, "Failed updating beacon data\n");
 
        if (changes & BSS_CHANGED_FTM_RESPONDER) {
                return -EINVAL;
        }
 
-       return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif);
+       return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif,
+                                              &mvm_sta->vif->bss_conf);
 }
 
 #ifdef CONFIG_NL80211_TESTMODE
 
                                            u32 action)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct ieee80211_bss_conf *link_conf;
+       unsigned int link_id;
 
        cmd->id_and_color = cpu_to_le32(mvmvif->id);
        cmd->action = cpu_to_le32(action);
 
        memcpy(cmd->local_mld_addr, vif->addr, ETH_ALEN);
 
-       cmd->filter_flags = cpu_to_le32(0);
-       cmd->he_support = cpu_to_le32(0);
-       cmd->eht_support = cpu_to_le32(0);
+       cmd->he_support = 0;
+       cmd->eht_support = 0;
+
+       /* should be set by specific context type handler */
+       cmd->filter_flags = 0;
 
        cmd->nic_not_ack_enabled =
                cpu_to_le32(!iwl_mvm_is_nic_ack_enabled(mvm, vif));
 
        if (iwlwifi_mod_params.disable_11ax)
                return;
-       cmd->he_support = cpu_to_le32(vif->bss_conf.he_support);
 
-       if (!iwlwifi_mod_params.disable_11be && cmd->he_support)
-               cmd->eht_support = cpu_to_le32(vif->bss_conf.eht_support);
+       /* If we have MLO enabled, then the firmware needs to enable
+        * address translation for the station(s) we add. That depends
+        * on having EHT enabled in firmware, which in turn depends on
+        * mac80211 in the code below.
+        * However, mac80211 doesn't enable HE/EHT until it has parsed
+        * the association response successfully, so just skip all that
+        * and enable both when we have MLO.
+        */
+       if (vif->valid_links) {
+               cmd->he_support = cpu_to_le32(1);
+               cmd->eht_support = cpu_to_le32(1);
+               return;
+       }
+
+       rcu_read_lock();
+       for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) {
+               link_conf = rcu_dereference(vif->link_conf[link_id]);
+               if (!link_conf)
+                       continue;
+
+               if (link_conf->he_support)
+                       cmd->he_support = cpu_to_le32(1);
+
+               /* it's not reasonable to have EHT without HE and FW API doesn't
+                * support it. Ignore EHT in this case.
+                */
+               if (!link_conf->he_support && link_conf->eht_support)
+                       continue;
+
+               if (link_conf->eht_support) {
+                       cmd->eht_support = cpu_to_le32(1);
+                       break;
+               }
+       }
+       rcu_read_unlock();
 }
 
 static int iwl_mvm_mld_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
                cmd.client.ctwin =
                        iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(mvm, vif);
 
+       /* FIXME: assume for now that DTIM period is the same for all links */
        if (vif->cfg.assoc && vif->bss_conf.dtim_period &&
            !force_assoc_off) {
                struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
 
        mutex_lock(&mvm->mutex);
 
-       /* Send the beacon template */
-       ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif);
-       if (ret)
-               goto out_unlock;
-
        /* No need to re-calculate the tsf_is, as it was offloaded */
 
        /* Add the mac context */
        if (ret)
                goto out_unlock;
 
+       /* Send the beacon template */
+       ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf);
+       if (ret)
+               goto out_unlock;
+
        /* Add link and activate it */
        ret = iwl_mvm_add_link(mvm, vif);
        if (ret)
 
        /* Need to send a new beacon template to the FW */
        if (changes & BSS_CHANGED_BEACON &&
-           iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
+           iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, &vif->bss_conf))
                IWL_WARN(mvm, "Failed updating beacon data\n");
 
        if (changes & BSS_CHANGED_FTM_RESPONDER) {
 
                             bool force_assoc_off, const u8 *bssid_override);
 int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
-                                   struct ieee80211_vif *vif);
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_bss_conf *link_conf);
 int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
                                 struct ieee80211_vif *vif,
-                                struct sk_buff *beacon);
+                                struct sk_buff *beacon,
+                                struct ieee80211_bss_conf *link_conf);
 int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
                                     struct sk_buff *beacon,
                                     void *data, int len);