#define NUM_MAC_INDEX          (NUM_MAC_INDEX_DRIVER + 1)
 #define NUM_MAC_INDEX_CDB      (NUM_MAC_INDEX_DRIVER + 2)
 
-#define IWL_MVM_STATION_COUNT          16
+#define IWL_MVM_STATION_COUNT_MAX      16
 #define IWL_MVM_INVALID_STA            0xFF
 
 enum iwl_ac {
 
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright (C) 2018 Intel Corporation
+ * Copyright(c) 2012 - 2014, 2018, 2020 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
- * Copyright (C) 2018 Intel Corporation
+ * Copyright(c) 2012 - 2014, 2018, 2020 Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
        __le32 air_time[MAC_INDEX_AUX];
        __le32 byte_count[MAC_INDEX_AUX];
        __le32 pkt_count[MAC_INDEX_AUX];
-       u8 avg_energy[IWL_MVM_STATION_COUNT];
+       u8 avg_energy[IWL_MVM_STATION_COUNT_MAX];
 } __packed; /* STATISTICS_RX_MAC_STATION_S_VER_3 */
 
 struct mvm_statistics_load_v1 {
        __le32 air_time[NUM_MAC_INDEX];
        __le32 byte_count[NUM_MAC_INDEX];
        __le32 pkt_count[NUM_MAC_INDEX];
-       u8 avg_energy[IWL_MVM_STATION_COUNT];
+       u8 avg_energy[IWL_MVM_STATION_COUNT_MAX];
 } __packed; /* STATISTICS_RX_MAC_STATION_S_VER_1 */
 
 struct mvm_statistics_rx {
 
 };
 
 #define IWL_UCODE_TLV_DEBUG_BASE       0x1000005
+#define IWL_UCODE_TLV_CONST_BASE       0x100
 
 /*
  * new TLV uCode file layout
        IWL_UCODE_TLV_FW_RECOVERY_INFO  = 57,
        IWL_UCODE_TLV_FW_FSEQ_VERSION   = 60,
 
+       IWL_UCODE_TLV_FW_NUM_STATIONS           = IWL_UCODE_TLV_CONST_BASE + 0,
+
        IWL_UCODE_TLV_TYPE_DEBUG_INFO           = IWL_UCODE_TLV_DEBUG_BASE + 0,
        IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION    = IWL_UCODE_TLV_DEBUG_BASE + 1,
        IWL_UCODE_TLV_TYPE_HCMD                 = IWL_UCODE_TLV_DEBUG_BASE + 2,
 
        u32 flags;
        u32 error_log_addr;
        u32 error_log_size;
+       u32 num_stations;
        unsigned long _api[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_API)];
        unsigned long _capa[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_CAPA)];
 
 
 #include "iwl-config.h"
 #include "iwl-modparams.h"
 #include "fw/api/alive.h"
+#include "fw/api/mac.h"
 
 /******************************************************************************
  *
                                 fseq_ver->version);
                        }
                        break;
+               case IWL_UCODE_TLV_FW_NUM_STATIONS:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       if (le32_to_cpup((__le32 *)tlv_data) >
+                           IWL_MVM_STATION_COUNT_MAX) {
+                               IWL_ERR(drv,
+                                       "%d is an invalid number of station\n",
+                                       le32_to_cpup((__le32 *)tlv_data));
+                               goto tlv_error;
+                       }
+                       capa->num_stations =
+                               le32_to_cpup((__le32 *)tlv_data);
+                       break;
                case IWL_UCODE_TLV_UMAC_DEBUG_ADDRS: {
                        struct iwl_umac_debug_addrs *dbg_ptrs =
                                (void *)tlv_data;
        fw->ucode_capa.standard_phy_calibration_size =
                        IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE;
        fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS;
+       fw->ucode_capa.num_stations = IWL_MVM_STATION_COUNT_MAX;
        /* dump all fw memory areas by default */
        fw->dbg.dump_mask = 0xffffffff;
 
 
 
        if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
                return -EINVAL;
-       if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT)
+       if (sta_id < 0 || sta_id >= mvm->fw->ucode_capa.num_stations)
                return -EINVAL;
        if (drain < 0 || drain > 1)
                return -EINVAL;
 
        mutex_lock(&mvm->mutex);
 
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
                pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i);
                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
                                                lockdep_is_held(&mvm->mutex));
 
        }
 
        /* init the fw <-> mac80211 STA mapping */
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++)
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++)
                RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
 
        mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA;
                goto error;
 
        /* init the fw <-> mac80211 STA mapping */
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++)
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++)
                RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
 
        /* Add auxiliary station for scanning */
 
                 * allow multicast data frames only as long as the station is
                 * authorized, i.e., GTK keys are already installed (if needed)
                 */
-               if (ap_sta_id < IWL_MVM_STATION_COUNT) {
+               if (ap_sta_id < mvm->fw->ucode_capa.num_stations) {
                        struct ieee80211_sta *sta;
 
                        rcu_read_lock();
 
                        iwl_mvm_vif_from_mac80211(info->control.vif);
                u8 ap_sta_id = READ_ONCE(mvmvif->ap_sta_id);
 
-               if (ap_sta_id < IWL_MVM_STATION_COUNT) {
+               if (ap_sta_id < mvm->fw->ucode_capa.num_stations) {
                        /* mac80211 holds rcu read lock */
                        sta = rcu_dereference(mvm->fw_id_to_mac_id[ap_sta_id]);
                        if (IS_ERR_OR_NULL(sta))
        struct iwl_mvm_sta *mvmsta;
        bool sleeping = (notif->type != IWL_MVM_PM_EVENT_AWAKE);
 
-       if (WARN_ON(notif->sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)))
+       if (WARN_ON(notif->sta_id >= mvm->fw->ucode_capa.num_stations))
                return;
 
        rcu_read_lock();
        }
 
        mutex_lock(&mvm->mutex);
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
                struct ieee80211_sta *sta;
 
                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
        mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
        /* flush the AP-station and all TDLS peers */
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
                                                lockdep_is_held(&mvm->mutex));
                if (IS_ERR_OR_NULL(sta))
 
 
        /* data related to data path */
        struct iwl_rx_phy_info last_phy_info;
-       struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
+       struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT_MAX];
        u8 rx_ba_sessions;
 
        /* configured by mac80211 */
 {
        struct ieee80211_sta *sta;
 
-       if (sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))
+       if (sta_id >= mvm->fw->ucode_capa.num_stations)
                return NULL;
 
        sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
 {
        struct ieee80211_sta *sta;
 
-       if (sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))
+       if (sta_id >= mvm->fw->ucode_capa.num_stations)
                return NULL;
 
        sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
 
        enum iwl_amsdu_size rb_size_default;
 
        /*
-        * We use IWL_MVM_STATION_COUNT to check the validity of the station
+        * We use IWL_MVM_STATION_COUNT_MAX to check the validity of the station
         * index all over the driver - check that its value corresponds to the
         * array size.
         */
-       BUILD_BUG_ON(ARRAY_SIZE(mvm->fw_id_to_mac_id) != IWL_MVM_STATION_COUNT);
+       BUILD_BUG_ON(ARRAY_SIZE(mvm->fw_id_to_mac_id) !=
+                    IWL_MVM_STATION_COUNT_MAX);
 
        /********************************
         * 1. Allocating and configuring HW data
                mvm->tvqm_info[hw_queue].sta_id :
                mvm->queue_info[hw_queue].ra_sta_id;
 
-       if (WARN_ON_ONCE(sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)))
+       if (WARN_ON_ONCE(sta_id >= mvm->fw->ucode_capa.num_stations))
                return;
 
        rcu_read_lock();
 
 
                id >>= RX_MDPU_RES_STATUS_STA_ID_SHIFT;
 
-               if (!WARN_ON_ONCE(id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) {
+               if (!WARN_ON_ONCE(id >= mvm->fw->ucode_capa.num_stations)) {
                        sta = rcu_dereference(mvm->fw_id_to_mac_id[id]);
                        if (IS_ERR(sta))
                                sta = NULL;
        }
 
        rcu_read_lock();
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
                struct iwl_mvm_sta *sta;
 
                if (!energy[i])
 
        if (desc->status & cpu_to_le32(IWL_RX_MPDU_STATUS_SRC_STA_FOUND)) {
                u8 id = le32_get_bits(desc->status, IWL_RX_MPDU_STATUS_STA_ID);
 
-               if (!WARN_ON_ONCE(id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) {
+               if (!WARN_ON_ONCE(id >= mvm->fw->ucode_capa.num_stations)) {
                        sta = rcu_dereference(mvm->fw_id_to_mac_id[id]);
                        if (IS_ERR(sta))
                                sta = NULL;
 
        int sta_id;
        u32 reserved_ids = 0;
 
-       BUILD_BUG_ON(IWL_MVM_STATION_COUNT > 32);
+       BUILD_BUG_ON(IWL_MVM_STATION_COUNT_MAX > 32);
        WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status));
 
        lockdep_assert_held(&mvm->mutex);
                reserved_ids = BIT(0);
 
        /* Don't take rcu_read_lock() since we are protected by mvm->mutex */
-       for (sta_id = 0; sta_id < ARRAY_SIZE(mvm->fw_id_to_mac_id); sta_id++) {
+       for (sta_id = 0; sta_id < mvm->fw->ucode_capa.num_stations; sta_id++) {
                if (BIT(sta_id) & reserved_ids)
                        continue;
 
        struct ieee80211_sta *sta;
        u32 sta_id = le32_to_cpu(notif->sta_id);
 
-       if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT))
+       if (WARN_ON_ONCE(sta_id >= mvm->fw->ucode_capa.num_stations))
                return;
 
        rcu_read_lock();
        lockdep_assert_held(&mvm->mutex);
 
        /* Block/unblock all the stations of the given mvmvif */
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
                                                lockdep_is_held(&mvm->mutex));
                if (IS_ERR_OR_NULL(sta))
 
 #include <linux/wait.h>
 
 #include "iwl-trans.h" /* for IWL_MAX_TID_COUNT */
-#include "fw-api.h" /* IWL_MVM_STATION_COUNT */
+#include "fw-api.h" /* IWL_MVM_STATION_COUNT_MAX */
 #include "rs.h"
 
 struct iwl_mvm;
 
  *
  * Copyright(c) 2014 Intel Mobile Communications GmbH
  * Copyright(c) 2017 Intel Deutschland GmbH
- * Copyright(C) 2018 - 2019 Intel Corporation
+ * Copyright(C) 2018 - 2020 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
  *
  * Copyright(c) 2014 Intel Mobile Communications GmbH
  * Copyright(c) 2017 Intel Deutschland GmbH
- * Copyright(C) 2018 - 2019 Intel Corporation
+ * Copyright(C) 2018 - 2020 Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
        lockdep_assert_held(&mvm->mutex);
 
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
                                                lockdep_is_held(&mvm->mutex));
                if (!sta || IS_ERR(sta) || !sta->tdls)
 
        lockdep_assert_held(&mvm->mutex);
 
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
                                                lockdep_is_held(&mvm->mutex));
                if (!sta || IS_ERR(sta) || !sta->tdls)
 
        /* populate TDLS peer data */
        cnt = 0;
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
                                                lockdep_is_held(&mvm->mutex));
                if (IS_ERR_OR_NULL(sta) || !sta->tdls)
                return;
        }
 
-       if (WARN_ON(sta_id >= IWL_MVM_STATION_COUNT))
+       if (WARN_ON(sta_id >= mvm->fw->ucode_capa.num_stations))
                return;
 
        sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
 
        struct iwl_mvm_sta *mvmsta;
        int i, err;
 
-       for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
+       for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
                mvmsta = iwl_mvm_sta_from_staid_protected(mvm, i);
                if (!mvmsta)
                        continue;
 
        struct sk_buff *skb;
        int freed;
 
-       if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT ||
+       if (WARN_ONCE(sta_id >= mvm->fw->ucode_capa.num_stations ||
                      tid > IWL_MAX_TID_COUNT,
                      "sta_id %d tid %d", sta_id, tid))
                return;