New wmi event "WMI_TLV_IFACE_COMBINATION_EVENTID" is used.
If WMI_SERVICE_IFACE_COMBINATION_SUPPORT service bit set and
WMI_TLV_IFACE_COMBINATION_EVENTID event got from FW side, then
interface combinations reported from FW will override the default
combinations which is hard-coded in host drivers.

Tested HW: WCN3990
Tested FW: WLAN.HL.3.1-01061-QCAHLSWMTPL-1

Signed-off-by: Zhonglin Zhang <[email protected]>
---
 drivers/net/wireless/ath/ath10k/core.c    |   2 +
 drivers/net/wireless/ath/ath10k/core.h    |  36 +++++
 drivers/net/wireless/ath/ath10k/mac.c     |  12 ++
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 183 ++++++++++++++++++++++-
 drivers/net/wireless/ath/ath10k/wmi-tlv.h | 232 ++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.h     |   2 +
 6 files changed, 466 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index dc45d16..29d558a 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -3210,6 +3210,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, 
struct device *dev,
                  ath10k_core_set_coverage_class_work);
 
        init_dummy_netdev(&ar->napi_dev);
+       ath10k_init_iface_comb(ar);
 
        ret = ath10k_coredump_create(ar);
        if (ret)
@@ -3248,6 +3249,7 @@ void ath10k_core_destroy(struct ath10k *ar)
        ath10k_coredump_destroy(ar);
        ath10k_htt_tx_destroy(&ar->htt);
        ath10k_wmi_free_host_mem(ar);
+       ath10k_deinit_iface_comb(ar);
        ath10k_mac_destroy(ar);
 }
 EXPORT_SYMBOL(ath10k_core_destroy);
diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 4d7db07..4ec7517 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -40,6 +40,9 @@
 #define ATH10K_NUM_CHANS 41
 #define ATH10K_MAX_5G_CHAN 173
 
+#define MAX_NUM_IFACE_COMBINATIONS  16
+#define BEACON_TX_OFFLOAD_MAX_VDEV  2
+
 /* Antenna noise floor */
 #define ATH10K_DEFAULT_NOISE_FLOOR -95
 
@@ -940,6 +943,13 @@ struct ath10k_bus_params {
        bool hl_msdu_ids;
 };
 
+struct ath10k_iface_comb {
+       struct ieee80211_iface_combination combo[MAX_NUM_IFACE_COMBINATIONS];
+       u16 combo_sz;
+       u16 interface_modes;
+       u32 beacon_tx_offload_max_vdev;
+};
+
 struct ath10k {
        struct ath_common ath_common;
        struct ieee80211_hw *hw;
@@ -1211,10 +1221,36 @@ struct ath10k {
        struct ath10k_bus_params bus_param;
        struct completion peer_delete_done;
 
+       /* iface combination */
+       struct ath10k_iface_comb iface;
+
        /* must be last */
        u8 drv_priv[0] __aligned(sizeof(void *));
 };
 
+static inline void ath10k_init_iface_comb(struct ath10k *ar)
+{
+       memset(&ar->iface, 0, sizeof(struct ath10k_iface_comb));
+       ar->iface.beacon_tx_offload_max_vdev = BEACON_TX_OFFLOAD_MAX_VDEV;
+}
+
+static inline void ath10k_deinit_iface_comb(struct ath10k *ar)
+{
+       int i;
+
+       for (i = 0; i < ar->iface.combo_sz; i++) {
+               kfree(ar->iface.combo[i].limits);
+               ar->iface.combo[i].limits = NULL;
+       }
+}
+
+static inline void ath10k_iface_comb_assignment(struct ath10k *ar)
+{
+       ar->hw->wiphy->iface_combinations = ar->iface.combo;
+       ar->hw->wiphy->n_iface_combinations = ar->iface.combo_sz;
+       ar->hw->wiphy->interface_modes = ar->iface.interface_modes;
+}
+
 static inline bool ath10k_peer_stats_enabled(struct ath10k *ar)
 {
        if (test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) &&
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index e43a566..0e90f30 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -8913,6 +8913,18 @@ int ath10k_mac_register(struct ath10k *ar)
                                ARRAY_SIZE(ath10k_tlv_if_comb);
                }
                ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+
+               if (test_bit
+                   (WMI_SERVICE_IFACE_COMBINATION_SUPPORT, ar->wmi.svc_map)) {
+                       /**
+                        * If combo_sz is not ZERO, it means that host will use
+                        * iface_combinations reported from FW.
+                        */
+                       if (ar->iface.combo_sz)
+                               ath10k_iface_comb_assignment(ar);
+                       else
+                               ath10k_warn(ar, "iface combination event 
missing!\n");
+               }
                break;
        case ATH10K_FW_WMI_OP_VERSION_10_1:
        case ATH10K_FW_WMI_OP_VERSION_10_2:
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c 
b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 2985bb1..ce89e96 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -64,6 +64,12 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
                = { .min_len = sizeof(struct wmi_tlv_wow_event_info) },
        [WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT]
                = { .min_len = sizeof(struct wmi_tlv_tx_pause_ev) },
+       [WMI_TLV_TAG_STRUCT_IFACE_COMBINATION_IND_EVENT]
+               = { .min_len = sizeof(struct wmi_tlv_iface_combination_event) },
+       [WMI_TLV_TAG_STRUCT_IFACE_COMBINATION]
+               = { .min_len = sizeof(struct wmi_tlv_iface_combination) },
+       [WMI_TLV_TAG_STRUCT_IFACE_LIMIT]
+               = { .min_len = sizeof(struct wmi_tlv_iface_limit) },
 };
 
 static int
@@ -483,6 +489,177 @@ static int ath10k_wmi_tlv_event_peer_delete_resp(struct 
ath10k *ar,
        return 0;
 }
 
+static u16 ath10k_wmi_tlv_vdev_type_remap(struct wmi_tlv_iface_limit *limit)
+{
+       u32 vdev_has_type = __le32_to_cpu(limit->vdev_type);
+       u32 vdev_has_subtype = __le32_to_cpu(limit->vdev_subtype);
+       u16 type = 0;
+
+       if (vdev_has_subtype) {
+               if (vdev_has_subtype & BIT(WMI_VDEV_SUBTYPE_P2P_DEVICE))
+                       type |= BIT(NL80211_IFTYPE_P2P_DEVICE);
+               if (vdev_has_subtype & BIT(WMI_VDEV_SUBTYPE_P2P_CLIENT))
+                       type |= BIT(NL80211_IFTYPE_P2P_CLIENT);
+               if (vdev_has_subtype & BIT(WMI_VDEV_SUBTYPE_P2P_GO))
+                       type |= BIT(NL80211_IFTYPE_P2P_GO);
+       } else {
+               if (vdev_has_type & BIT(WMI_VDEV_TYPE_AP))
+                       type |= BIT(NL80211_IFTYPE_AP);
+               if (vdev_has_type & BIT(WMI_VDEV_TYPE_STA))
+                       type |= BIT(NL80211_IFTYPE_STATION);
+               if (vdev_has_type & BIT(WMI_VDEV_TYPE_IBSS))
+                       type |= BIT(NL80211_IFTYPE_ADHOC);
+       }
+
+       return type;
+}
+
+static int ath10k_wmi_tlv_iface_comb_parse(struct ath10k *ar, u16 tag, u16 len,
+                                          const void *ptr, void *data)
+{
+       int ret = 0;
+       unsigned long valid_fields = 0;
+       struct wmi_tlv_iface_comb_parse *p = data;
+       struct ieee80211_iface_combination *comb = &ar->iface.combo[0];
+       struct ieee80211_iface_limit *limit = NULL;
+
+       switch (tag) {
+       case WMI_TLV_TAG_STRUCT_IFACE_COMBINATION_IND_EVENT:
+               p->ev = (struct wmi_tlv_iface_combination_event *)ptr;
+               break;
+       case WMI_TLV_TAG_ARRAY_STRUCT:
+               ret = ath10k_wmi_tlv_iter(ar, ptr, len,
+                                         ath10k_wmi_tlv_iface_comb_parse, p);
+               break;
+       case WMI_TLV_TAG_STRUCT_IFACE_COMBINATION:
+               p->combs = (struct wmi_tlv_iface_combination *)ptr;
+
+               if (p->n_combs >= MAX_NUM_IFACE_COMBINATIONS) {
+                       ath10k_warn(ar, "Exceed Max Num Iface Combinations!\n");
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               valid_fields = __le32_to_cpu(p->combs->valid_fields);
+
+               if (test_bit(WMI_TLV_IFACE_COMB_BCN_INT_MATCH_VALID_BIT,
+                            &valid_fields))
+                       comb[p->n_combs].beacon_int_infra_match =
+                               __le32_to_cpu(p->combs->beacon_int_infra_match);
+
+               if (test_bit(WMI_TLV_IFACE_COMB_BCN_INT_MIN_GCD_VALID_BIT,
+                            &valid_fields))
+                       comb[p->n_combs].beacon_int_min_gcd =
+                               __le32_to_cpu(p->combs->beacon_int_min_gcd);
+
+               comb[p->n_combs].limits =
+                       kcalloc(p->combs->limits_n, sizeof(*limit), GFP_ATOMIC);
+               if (!comb[p->n_combs].limits) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               p->n_combs++;
+               ar->iface.combo_sz++;
+               break;
+       case WMI_TLV_TAG_STRUCT_IFACE_LIMIT:
+               p->limits = (struct wmi_tlv_iface_limit *)ptr;
+
+               /**
+                * p->comb_index: current iface combo index, default value 0
+                * comb[p->comb_index]: current iface comb
+                * p->limit_index: point to the next available iface limit slot,
+                * limit_index default value 0.
+                * comb[p->comb_index].n_limits: num of limits of this
+                * comb_index. n_limits value got from
+                * WMI_TLV_TAG_STRUCT_IFACE_COMBINATION assignment.
+                *
+                * So the logic here:
+                * 0) Basic precondition now we have got all comb(s) in
+                *    WMI_TLV_TAG_STRUCT_IFACE_COMBINATION assignment.
+                * 1) if (limit_index >= n_limits of current iface combo, then
+                *    this new iface limit will belong to a new iface combo. So
+                *    update the index
+                *    a. comb_index++ and limit_index reset as 0.
+                *    b. comb_fill_max_interfaces point to the current iface
+                *       combo to fill max_interfaces field. And its default
+                *       value should point to the first iface combo.
+                * 2) Use combo_index/limit_index to do assignment, and finally
+                *    limit_index++ to point to the next available limit slot.
+                * 3) Loop to 1) when find new iface limit, else exit the parse
+                *    procedure.
+                */
+               if (p->limit_index >= comb[p->comb_index].n_limits) {
+                       p->comb_index++;
+                       p->limit_index = 0;
+                       p->comb_fill_max_interfaces = &comb[p->comb_index];
+               }
+
+               limit = (struct ieee80211_iface_limit *)
+                         &comb[p->comb_index].limits[p->limit_index];
+               limit->max = __le32_to_cpu(p->limits->vdev_limit_n);
+               limit->types = ath10k_wmi_tlv_vdev_type_remap(p->limits);
+               ar->iface.interface_modes |= limit->types;
+
+               /**
+                * ar->iface.beacon_tx_offload_max_vdev default value is 2.
+                * If limit type is AP and
+                * limit->max > ar->iface.beacon_tx_offload_max_vdev, we will
+                * override this value by limit->max.  FW needs this value in
+                * WMI_INIT command for beacon offload function.
+                */
+               if ((limit->types & BIT(NL80211_IFTYPE_AP)) &&
+                   limit->max > ar->iface.beacon_tx_offload_max_vdev)
+                       ar->iface.beacon_tx_offload_max_vdev = limit->max;
+               if (!p->comb_fill_max_interfaces)
+                       /* point to the first combination */
+                       p->comb_fill_max_interfaces = comb;
+
+               p->comb_fill_max_interfaces->max_interfaces += limit->max;
+
+               p->limit_index++;
+               break;
+       default:
+               break;
+       }
+out:
+       if (ret) {
+               int i;
+
+               for (i = 0; i < p->n_combs; i++) {
+                       kfree(comb[i].limits);
+                       comb[i].limits = NULL;
+               }
+       }
+       return ret;
+}
+
+static int ath10k_wmi_tlv_iface_combination(struct ath10k *ar,
+                                           struct sk_buff *skb)
+{
+       int ret;
+       struct wmi_tlv_iface_comb_parse parse;
+
+       if (!test_bit(WMI_SERVICE_IFACE_COMBINATION_SUPPORT, ar->wmi.svc_map))
+               return 0;
+
+       memset(&parse, 0, sizeof(struct wmi_tlv_iface_comb_parse));
+
+       ath10k_deinit_iface_comb(ar);
+       ath10k_init_iface_comb(ar);
+
+       ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len,
+                                 ath10k_wmi_tlv_iface_comb_parse, &parse);
+
+       if (ret) {
+               ath10k_warn(ar, "%s:failed to parse tlv: %d\n", __func__, ret);
+               ar->iface.combo_sz = 0;
+               return ret;
+       }
+
+       return 0;
+}
+
 /***********/
 /* TLV ops */
 /***********/
@@ -608,6 +785,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct 
sk_buff *skb)
        case WMI_TLV_SERVICE_READY_EVENTID:
                ath10k_wmi_event_service_ready(ar, skb);
                return;
+       case WMI_TLV_IFACE_COMBINATION_EVENTID:
+               ath10k_wmi_tlv_iface_combination(ar, skb);
+               break;
        case WMI_TLV_READY_EVENTID:
                ath10k_wmi_event_ready(ar, skb);
                break;
@@ -1776,7 +1956,8 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct 
ath10k *ar)
        cfg->max_frag_entries = __cpu_to_le32(2);
        cfg->num_tdls_vdevs = __cpu_to_le32(TARGET_TLV_NUM_TDLS_VDEVS);
        cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20);
-       cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(2);
+       cfg->beacon_tx_offload_max_vdev =
+                       __cpu_to_le32(ar->iface.beacon_tx_offload_max_vdev);
        cfg->num_multicast_filter_entries = __cpu_to_le32(5);
        cfg->num_wow_filters = __cpu_to_le32(ar->wow.max_num_patterns);
        cfg->num_keep_alive_pattern = __cpu_to_le32(6);
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h 
b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index d691f06..71d7f396 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -288,6 +288,7 @@ enum wmi_tlv_event_id {
        WMI_TLV_SERVICE_READY_EVENTID = 0x1,
        WMI_TLV_READY_EVENTID,
        WMI_TLV_SERVICE_AVAILABLE_EVENTID,
+       WMI_TLV_IFACE_COMBINATION_EVENTID,
        WMI_TLV_SCAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SCAN),
        WMI_TLV_PDEV_TPC_CONFIG_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PDEV),
        WMI_TLV_CHAN_INFO_EVENTID,
@@ -1217,6 +1218,121 @@ enum wmi_tlv_tag {
        WMI_TLV_TAG_STRUCT_FD_SEND_FROM_HOST_CMD,
        WMI_TLV_TAG_STRUCT_ENABLE_FILS_CMD,
        WMI_TLV_TAG_STRUCT_HOST_SWFDA_EVENT,
+       WMI_TLV_TAG_STRUCT_BCN_OFFLOAD_CTRL_CMD,
+       WMI_TLV_TAG_STRUCT_PDEV_SET_AC_TXQ_OPTIMIZED_CMD,
+       WMI_TLV_TAG_STRUCT_STATS_PERIOD,
+       WMI_TLV_TAG_STRUCT_NDL_SCHEDULE_UPDATE,
+       WMI_TLV_TAG_STRUCT_PEER_TID_MSDUQ_QDEPTH_THRESH_UPDATE_CMD,
+       WMI_TLV_TAG_STRUCT_MSDUQ_QDEPTH_THRESH_UPDATE,
+       WMI_TLV_TAG_STRUCT_PDEV_SET_RX_FILTER_PROMISCUOUS_CMD,
+       WMI_TLV_TAG_STRUCT_SAR2_RESULT_EVENT,
+       WMI_TLV_TAG_STRUCT_SAR_CAPABILITIES,
+       WMI_TLV_TAG_STRUCT_SAP_OBSS_DETECTION_CFG_CMD,
+       WMI_TLV_TAG_STRUCT_SAP_OBSS_DETECTION_INFO_EVENT,
+       WMI_TLV_TAG_STRUCT_DMA_RING_CAPABILITIES,
+       WMI_TLV_TAG_STRUCT_DMA_RING_CFG_REQ,
+       WMI_TLV_TAG_STRUCT_DMA_RING_CFG_RSP,
+       WMI_TLV_TAG_STRUCT_DMA_BUF_RELEASE,
+       WMI_TLV_TAG_STRUCT_DMA_BUF_RELEASE_ENTRY,
+       WMI_TLV_TAG_STRUCT_SAR_GET_LIMITS_CMD,
+       WMI_TLV_TAG_STRUCT_SAR_GET_LIMITS_EVENT,
+       WMI_TLV_TAG_STRUCT_SAR_GET_LIMITS_EVENT_ROW,
+       WMI_TLV_TAG_STRUCT_OFFLOAD_11K_REPORT,
+       WMI_TLV_TAG_STRUCT_INVOKE_NEIGHBOR_REPORT,
+       WMI_TLV_TAG_STRUCT_NEIGHBOR_REPORT_OFFLOAD_TLV_PARAM,
+       WMI_TLV_TAG_STRUCT_VDEV_SET_CONNECTIVITY_CHECK_STATS,
+       WMI_TLV_TAG_STRUCT_VDEV_GET_CONNECTIVITY_CHECK_STATS,
+       WMI_TLV_TAG_STRUCT_BPF_SET_VDEV_ENABLE_CMD,
+       WMI_TLV_TAG_STRUCT_BPF_SET_VDEV_WORK_MEMORY_CMD,
+       WMI_TLV_TAG_STRUCT_BPF_GET_VDEV_WORK_MEMORY_CMD,
+       WMI_TLV_TAG_STRUCT_BPF_GET_VDEV_WORK_MEMORY_RESP_EVENT,
+       WMI_TLV_TAG_STRUCT_PDEV_GET_NFCAL_POWER,
+       WMI_TLV_TAG_STRUCT_BSS_COLOR_CHANGE_ENABLE,
+       WMI_TLV_TAG_STRUCT_OBSS_COLOR_COLLISION_DET_CONFIG,
+       WMI_TLV_TAG_STRUCT_OBSS_COLOR_COLLISION_EVENT,
+       WMI_TLV_TAG_STRUCT_RUNTIME_DPD_RECAL_CMD,
+       WMI_TLV_TAG_STRUCT_TWT_ENABLE_CMD,
+       WMI_TLV_TAG_STRUCT_TWT_DISABLE_CMD,
+       WMI_TLV_TAG_STRUCT_TWT_ADD_DIALOG_CMD,
+       WMI_TLV_TAG_STRUCT_TWT_DEL_DIALOG_CMD,
+       WMI_TLV_TAG_STRUCT_TWT_PAUSE_DIALOG_CMD,
+       WMI_TLV_TAG_STRUCT_TWT_RESUME_DIALOG_CMD,
+       WMI_TLV_TAG_STRUCT_TWT_ENABLE_COMPLETE_EVENT,
+       WMI_TLV_TAG_STRUCT_TWT_DISABLE_COMPLETE_EVENT,
+       WMI_TLV_TAG_STRUCT_TWT_ADD_DIALOG_COMPLETE_EVENT,
+       WMI_TLV_TAG_STRUCT_TWT_DEL_DIALOG_COMPLETE_EVENT,
+       WMI_TLV_TAG_STRUCT_TWT_PAUSE_DIALOG_COMPLETE_EVENT,
+       WMI_TLV_TAG_STRUCT_TWT_RESUME_DIALOG_COMPLETE_EVENT,
+       WMI_TLV_TAG_STRUCT_REQUEST_ROAM_SCAN_STATS_CMD,
+       WMI_TLV_TAG_STRUCT_ROAM_SCAN_STATS_EVENT,
+       WMI_TLV_TAG_STRUCT_PEER_TID_CONFIGURATIONS_CMD,
+       WMI_TLV_TAG_STRUCT_VDEV_SET_CUSTOM_SW_RETRY_TH_CMD,
+       WMI_TLV_TAG_STRUCT_GET_TPC_POWER_CMD,
+       WMI_TLV_TAG_STRUCT_GET_TPC_POWER_EVENT,
+       WMI_TLV_TAG_STRUCT_DMA_BUF_RELEASE_SPECTRAL_META_DATA,
+       WMI_TLV_TAG_STRUCT_MOTION_DET_CONFIG_PARAMS_CMD,
+       WMI_TLV_TAG_STRUCT_MOTION_DET_BASE_LINE_CONFIG_PARAMS_CMD,
+       WMI_TLV_TAG_STRUCT_MOTION_DET_START_STOP_CMD,
+       WMI_TLV_TAG_STRUCT_MOTION_DET_BASE_LINE_START_STOP_CMD,
+       WMI_TLV_TAG_STRUCT_MOTION_DET_EVENT,
+       WMI_TLV_TAG_STRUCT_MOTION_DET_BASE_LINE_EVENT,
+       WMI_TLV_TAG_STRUCT_NDP_TRANSPORT_IP_PARAM,
+       WMI_TLV_TAG_STRUCT_OBSS_SPATIAL_REUSE_SET_CMD,
+       WMI_TLV_TAG_STRUCT_ESP_ESTIMATE_EVENT,
+       WMI_TLV_TAG_STRUCT_NAN_HOST_CONFIG_PARAM,
+       WMI_TLV_TAG_STRUCT_SPECTRAL_BIN_SCALING_PARAM,
+       WMI_TLV_TAG_STRUCT_PEER_CFR_CAPTURE_CONF_CMD,
+       WMI_TLV_TAG_STRUCT_PEER_CHAN_WIDTH_SWITCH_CMD,
+       WMI_TLV_TAG_STRUCT_CHAN_WIDTH_PEER_LIST,
+       WMI_TLV_TAG_STRUCT_OBSS_SPATIAL_REUSE_SET_DEF_OBSS_THRESH_CMD,
+       WMI_TLV_TAG_STRUCT_PDEV_HE_TB_ACTION_FRM_CMD,
+       WMI_TLV_TAG_STRUCT_PEER_EXTD2_STATS,
+       WMI_TLV_TAG_STRUCT_HPCS_PULSE_START_CMD,
+       WMI_TLV_TAG_STRUCT_PDEV_CTL_FAILSAFE_CHECK_PARAM,
+       WMI_TLV_TAG_STRUCT_VDEV_CHAINMASK_CONFIG_CMD,
+       WMI_TLV_TAG_STRUCT_VDEV_BCN_OFFLOAD_QUIET_CONFIG_CMD,
+       WMI_TLV_TAG_STRUCT_NAN_EVENT_INFO,
+       WMI_TLV_TAG_STRUCT_NDP_CHANNEL_INFO,
+       WMI_TLV_TAG_STRUCT_NDP_CMD,
+       WMI_TLV_TAG_STRUCT_NDP_EVENT,
+       WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_FILTER_CMD,
+       WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_FILTER_INFO,
+       WMI_TLV_TAG_STRUCT_QUIET_OFFLOAD_INFO,
+       WMI_TLV_TAG_STRUCT_GET_BCN_RECV_STATS,
+       WMI_TLV_TAG_STRUCT_VDEV_BCN_RECV_STATS_EVENT,
+       WMI_TLV_TAG_STRUCT_PEER_TX_PN_REQUEST_CMD,
+       WMI_TLV_TAG_STRUCT_PEER_TX_PN_RESPONSE_EVENT,
+       WMI_TLV_TAG_STRUCT_TLV_ARRAYS_LEN_PARAM,
+       WMI_TLV_TAG_STRUCT_PEER_UNMAP_RESPONSE_CMD,
+       WMI_TLV_TAG_STRUCT_PDEV_CSC_SWITCH_COUNT_STATUS_EVENT,
+       WMI_TLV_TAG_STRUCT_ROAM_BSS_LOAD_CONFIG_CMD,
+       WMI_TLV_TAG_STRUCT_ROAM_BLACKLIST_EVENT,
+       WMI_TLV_TAG_STRUCT_CSC_VDEV_LIST,
+       WMI_TLV_TAG_STRUCT_VDEV_GET_MWS_COEX_INFO_CMD,
+       WMI_TLV_TAG_STRUCT_VDEV_GET_MWS_COEX_STATE,
+       WMI_TLV_TAG_STRUCT_VDEV_GET_MWS_COEX_DPWB_STATE,
+       WMI_TLV_TAG_STRUCT_VDEV_GET_MWS_COEX_TDM_STATE,
+       WMI_TLV_TAG_STRUCT_VDEV_GET_MWS_COEX_IDRX_STATE,
+       WMI_TLV_TAG_STRUCT_VDEV_GET_MWS_COEX_ANTENNA_SHARING_STATE,
+       WMI_TLV_TAG_STRUCT_REQUEST_WLM_STATS_CMD,
+       WMI_TLV_TAG_STRUCT_WLM_STATS_EVENT,
+       WMI_TLV_TAG_STRUCT_KEY_MATERIAL_EXT,
+       WMI_TLV_TAG_STRUCT_PEER_CFR_CAPTURE_EVENT,
+       WMI_TLV_TAG_STRUCT_COLD_BOOT_CAL_DATA,
+       WMI_TLV_TAG_STRUCT_PDEV_SET_RAP_CONFIG,
+       WMI_TLV_TAG_STRUCT_PDEV_SET_RAP_CONFIG_ON_STA_PS,
+       WMI_TLV_TAG_STRUCT_PDEV_RAP_INFO_EVENT,
+       WMI_TLV_TAG_STRUCT_STA_TDCC_CONFIG_CMD,
+       WMI_TLV_TAG_STRUCT_ROAM_DEAUTH_CONFIG_CMD,
+       WMI_TLV_TAG_STRUCT_ROAM_IDLE_CONFIG_CMD,
+       WMI_TLV_TAG_STRUCT_IDLE_TRIGGER_MONITOR_CMD,
+       WMI_TLV_TAG_STRUCT_STATS_INTERFERENCE,
+       WMI_TLV_TAG_STRUCT_ROAM_SCORE_DELTA_PARAM,
+       WMI_TLV_TAG_STRUCT_ROAM_CND_MIN_RSSI_PARAM,
+       WMI_TLV_TAG_STRUCT_CHAN_RF_CHARACTERIZATION_INFO,
+       WMI_TLV_TAG_STRUCT_IFACE_COMBINATION_IND_EVENT,
+       WMI_TLV_TAG_STRUCT_IFACE_COMBINATION,
+       WMI_TLV_TAG_STRUCT_IFACE_LIMIT,
 
        WMI_TLV_TAG_MAX
 };
@@ -1409,6 +1525,7 @@ enum wmi_tlv_service {
        WMI_TLV_SERVICE_WLAN_HPCS_PULSE = 172,
        WMI_TLV_SERVICE_PER_VDEV_CHAINMASK_CONFIG_SUPPORT = 173,
        WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI = 174,
+       WMI_TLV_SERVICE_IFACE_COMBINATION_SUPPORT = 209,
 
        WMI_TLV_MAX_EXT_SERVICE = 256,
 };
@@ -1588,6 +1705,8 @@ wmi_tlv_svc_map_ext(const __le32 *in, unsigned long *out, 
size_t len)
               WMI_TLV_MAX_SERVICE);
        SVCMAP(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI,
               WMI_SERVICE_TX_DATA_ACK_RSSI, WMI_TLV_MAX_SERVICE);
+       SVCMAP(WMI_TLV_SERVICE_IFACE_COMBINATION_SUPPORT,
+              WMI_SERVICE_IFACE_COMBINATION_SUPPORT, WMI_TLV_MAX_SERVICE);
 }
 
 #undef SVCMAP
@@ -2483,4 +2602,117 @@ struct wmi_tlv_mgmt_tx_cmd {
        __le32 frame_len;
        __le32 buf_len;
 } __packed;
+
+struct wmi_tlv_iface_combination_event {
+       /* common part */
+       __le32 pdev_n;
+
+       /* iface combination part
+        * wmi_tlv_iface_combinations[] will follow.
+        * 1. iface combinations:
+        * wmi_tlv_iface_combination combinations[0];
+        * wmi_tlv_iface_combination combinations[.];
+        * wmi_tlv_iface_combination combinations[m];
+        * ===========================================
+        * 2. limits for all combinations:
+        * 2.1 limits for first combination:
+        * wmi_tlv_iface_limit limits[0];
+        * wmi_tlv_iface_limit limits[vdev_limit_n - 1];
+        * -------------------------------------------
+        * 2.2 limits for next combination:
+        * wmi_tlv_iface_limit limits[i];
+        * wmi_tlv_iface_limit limits[vdev_limit_n - 1];
+        * -------------------------------------------
+        * 2.3 limits for the last combination:
+        * wmi_tlv_iface_limit limits[m];
+        * wmi_tlv_iface_limit limits[vdev_limit_n - 1];
+        */
+} __packed;
+
+struct wmi_tlv_iface_limit {
+       /**
+        * How many vdevs can work as below vdev_type/vdev_subtype
+        * in one combination
+        */
+       __le32 vdev_limit_n;
+
+       /* Indicate what role above vdev can work as
+        * Refer to "WMI_VDEV_TYPE_xx, WMI_VDEV_SUBTYPE_xx
+        * for role definition
+        */
+       __le32 vdev_type;
+       __le32 vdev_subtype;
+} __packed;
+
+#define WMI_TLV_IFACE_COMB_PEER_MAX_VALID_BIT 0
+#define WMI_TLV_IFACE_COMB_BCN_INT_MATCH_VALID_BIT 1
+#define WMI_TLV_IFACE_COMB_BCN_INT_MIN_GCD_VALID_BIT 2
+#define WMI_TLV_IFACE_COMB_NUM_UNIQUE_BI_VALID_BIT 3
+
+struct wmi_tlv_iface_combination {
+       /**
+        * Max num peers can be supported in this combination.
+        * It excludes the self-peers associated with each vdev.
+        * It's the number of real remote peers.
+        * eg: when working as AP mode, indicating how many clients can be
+        * supported to connect with this AP.
+        */
+       __le32 peer_max;
+       /**
+        * Home channels supported on one single phy concurrently
+        */
+       __le32 channel_n;
+       /**
+        * The number of "wmi_tlv_iface_limit" for a specified combination.
+        */
+       __le32 limits_n;
+       /**
+        * Beacon intervals between infrastructure and AP types must match
+        * or not.
+        * 1: need match
+        * 0: not need
+        */
+       __le32 beacon_int_infra_match;
+       /**
+        * This interface (vdev) combination supports different beacon
+        * intervals.
+        *
+        * = 0
+        *   all beacon intervals for different interface must be same.
+        * > 0
+        *   any beacon interval for the interface part of this combination AND
+        *   GCD of all beacon intervals from beaconing interfaces of this
+        *   combination must be greater or equal to this value.
+        */
+       __le32 beacon_int_min_gcd;
+       /**
+        * Number of different beacon intervals supported.
+        */
+       __le32 num_unique_bi;
+       /**
+        * This indicates which field contains valid value from FW side.
+        * All fields except channel_n and limits_n are optional.
+        */
+       __le32 valid_fields;
+} __packed;
+
+/**
+ * It is to save the parse status. Through the parse procedure,
+ * iface_combinations info will be got finally.
+ */
+struct wmi_tlv_iface_comb_parse {
+       struct wmi_tlv_iface_combination_event *ev;
+       struct wmi_tlv_iface_combination *combs;
+       struct wmi_tlv_iface_limit *limits;
+       /* for combos fill */
+       int n_combs;
+       struct ieee80211_iface_combination *comb_fill_max_interfaces;
+
+       /* for limits fill
+        * comb_index point to the current combo
+        * limit_index point to the next available limit slot
+        */
+       int comb_index;
+       int limit_index;
+};
 #endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h 
b/drivers/net/wireless/ath/ath10k/wmi.h
index 838768c..cdba117 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -202,6 +202,7 @@ enum wmi_service {
        WMI_SERVICE_REPORT_AIRTIME,
        WMI_SERVICE_SYNC_DELETE_CMDS,
        WMI_SERVICE_TX_PWR_PER_PEER,
+       WMI_SERVICE_IFACE_COMBINATION_SUPPORT,
 
        /* Remember to add the new value to wmi_service_name()! */
 
@@ -496,6 +497,7 @@ static inline char *wmi_service_name(enum wmi_service 
service_id)
        SVCSTR(WMI_SERVICE_REPORT_AIRTIME);
        SVCSTR(WMI_SERVICE_SYNC_DELETE_CMDS);
        SVCSTR(WMI_SERVICE_TX_PWR_PER_PEER);
+       SVCSTR(WMI_SERVICE_IFACE_COMBINATION_SUPPORT);
 
        case WMI_SERVICE_MAX:
                return NULL;
-- 
2.7.4


_______________________________________________
ath10k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath10k

Reply via email to