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 <zhonglin@xxxxxxxxxxxxxx> --- 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