|
@@ -3518,6 +3518,301 @@ static inline void wma_update_target_vht_cap(tp_wma_handle wh,
|
|
|
cfg->vht_max_ampdu_len_exp);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * wma_derive_ext_ht_cap() - Derive HT caps based on given value
|
|
|
+ * @wma_handle: pointer to wma_handle
|
|
|
+ * @ht_cap: given pointer to HT caps which needs to be updated
|
|
|
+ * @tx_chain: given tx chainmask value
|
|
|
+ * @rx_chain: given rx chainmask value
|
|
|
+ * @value: new HT cap info provided in form of bitmask
|
|
|
+ *
|
|
|
+ * This function takes the value provided in form of bitmask and decodes
|
|
|
+ * it. After decoding, what ever value it gets, it takes the union(max) or
|
|
|
+ * intersection(min) with previously derived values.
|
|
|
+ *
|
|
|
+ * Return: none
|
|
|
+ *
|
|
|
+ */
|
|
|
+static void wma_derive_ext_ht_cap(tp_wma_handle wma_handle,
|
|
|
+ struct wma_tgt_ht_cap *ht_cap, uint32_t value,
|
|
|
+ uint32_t tx_chain, uint32_t rx_chain)
|
|
|
+{
|
|
|
+ struct wma_tgt_ht_cap tmp = {0};
|
|
|
+
|
|
|
+ if (NULL == wma_handle || NULL == ht_cap)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (0 == qdf_mem_cmp(ht_cap, &tmp, sizeof(struct wma_tgt_ht_cap))) {
|
|
|
+ ht_cap->ht_rx_stbc = (!!(value & WMI_HT_CAP_RX_STBC));
|
|
|
+ ht_cap->ht_tx_stbc = (!!(value & WMI_HT_CAP_TX_STBC));
|
|
|
+ ht_cap->mpdu_density = (!!(value & WMI_HT_CAP_MPDU_DENSITY));
|
|
|
+ ht_cap->ht_rx_ldpc = (!!(value & WMI_HT_CAP_RX_LDPC));
|
|
|
+ ht_cap->ht_sgi_20 = (!!(value & WMI_HT_CAP_HT20_SGI));
|
|
|
+ ht_cap->ht_sgi_40 = (!!(value & WMI_HT_CAP_HT40_SGI));
|
|
|
+ ht_cap->num_rf_chains =
|
|
|
+ QDF_MAX(wma_get_num_of_setbits_from_bitmask(tx_chain),
|
|
|
+ wma_get_num_of_setbits_from_bitmask(rx_chain));
|
|
|
+ } else {
|
|
|
+ ht_cap->ht_rx_stbc = QDF_MIN(ht_cap->ht_rx_stbc,
|
|
|
+ (!!(value & WMI_HT_CAP_RX_STBC)));
|
|
|
+ ht_cap->ht_tx_stbc = QDF_MAX(ht_cap->ht_tx_stbc,
|
|
|
+ (!!(value & WMI_HT_CAP_TX_STBC)));
|
|
|
+ ht_cap->mpdu_density = QDF_MIN(ht_cap->mpdu_density,
|
|
|
+ (!!(value & WMI_HT_CAP_MPDU_DENSITY)));
|
|
|
+ ht_cap->ht_rx_ldpc = QDF_MIN(ht_cap->ht_rx_ldpc,
|
|
|
+ (!!(value & WMI_HT_CAP_RX_LDPC)));
|
|
|
+ ht_cap->ht_sgi_20 = QDF_MIN(ht_cap->ht_sgi_20,
|
|
|
+ (!!(value & WMI_HT_CAP_HT20_SGI)));
|
|
|
+ ht_cap->ht_sgi_40 = QDF_MIN(ht_cap->ht_sgi_40,
|
|
|
+ (!!(value & WMI_HT_CAP_HT40_SGI)));
|
|
|
+ ht_cap->num_rf_chains =
|
|
|
+ QDF_MAX(ht_cap->num_rf_chains,
|
|
|
+ QDF_MAX(wma_get_num_of_setbits_from_bitmask(
|
|
|
+ tx_chain),
|
|
|
+ wma_get_num_of_setbits_from_bitmask(
|
|
|
+ rx_chain)));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * wma_update_target_ext_ht_cap() - Update HT caps with given extended cap
|
|
|
+ * @wma_handle: pointer to wma_handle
|
|
|
+ * @ht_cap: HT cap structure to be filled
|
|
|
+ *
|
|
|
+ * This function loop through each hardware mode and for each hardware mode
|
|
|
+ * again it loop through each MAC/PHY and pull the caps 2G and 5G specific
|
|
|
+ * HT caps and derives the final cap.
|
|
|
+ *
|
|
|
+ * Return: none
|
|
|
+ *
|
|
|
+ */
|
|
|
+static void wma_update_target_ext_ht_cap(tp_wma_handle wma_handle,
|
|
|
+ struct wma_tgt_ht_cap *ht_cap)
|
|
|
+{
|
|
|
+ int i, j = 0, max_mac;
|
|
|
+ uint32_t ht_2g, ht_5g;
|
|
|
+ struct wma_tgt_ht_cap tmp_ht_cap = {0}, tmp_cap = {0};
|
|
|
+ struct extended_caps *phy_caps;
|
|
|
+ WMI_MAC_PHY_CAPABILITIES *mac_cap;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * for legacy device extended cap might not even come, so in that case
|
|
|
+ * don't overwrite legacy values
|
|
|
+ */
|
|
|
+ if (!wma_handle ||
|
|
|
+ (0 == wma_handle->phy_caps.num_hw_modes.num_hw_modes)) {
|
|
|
+ WMA_LOGI("%s: No extended HT cap for current SOC", __func__);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ phy_caps = &wma_handle->phy_caps;
|
|
|
+ for (i = 0; i < phy_caps->num_hw_modes.num_hw_modes; i++) {
|
|
|
+ if (phy_caps->each_hw_mode_cap[i].phy_id_map == PHY1_PHY2)
|
|
|
+ max_mac = j + 2;
|
|
|
+ else
|
|
|
+ max_mac = j + 1;
|
|
|
+ for ( ; j < max_mac; j++) {
|
|
|
+ mac_cap = &phy_caps->each_phy_cap_per_hwmode[j];
|
|
|
+ ht_2g = mac_cap->ht_cap_info_2G;
|
|
|
+ ht_5g = mac_cap->ht_cap_info_5G;
|
|
|
+ if (ht_2g)
|
|
|
+ wma_derive_ext_ht_cap(wma_handle, &tmp_ht_cap,
|
|
|
+ ht_2g, mac_cap->tx_chain_mask_2G,
|
|
|
+ mac_cap->rx_chain_mask_2G);
|
|
|
+ if (ht_5g)
|
|
|
+ wma_derive_ext_ht_cap(wma_handle, &tmp_ht_cap,
|
|
|
+ ht_5g, mac_cap->tx_chain_mask_5G,
|
|
|
+ mac_cap->rx_chain_mask_5G);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (0 != qdf_mem_cmp(&tmp_cap, &tmp_ht_cap,
|
|
|
+ sizeof(struct wma_tgt_ht_cap))) {
|
|
|
+ qdf_mem_copy(ht_cap, &tmp_ht_cap,
|
|
|
+ sizeof(struct wma_tgt_ht_cap));
|
|
|
+ }
|
|
|
+
|
|
|
+ WMA_LOGI("%s: [ext ht cap] ht_rx_stbc - %d, ht_tx_stbc - %d\n\
|
|
|
+ mpdu_density - %d ht_rx_ldpc - %d ht_sgi_20 - %d\n\
|
|
|
+ ht_sgi_40 - %d num_rf_chains - %d ", __func__,
|
|
|
+ ht_cap->ht_rx_stbc, ht_cap->ht_tx_stbc,
|
|
|
+ ht_cap->mpdu_density, ht_cap->ht_rx_ldpc,
|
|
|
+ ht_cap->ht_sgi_20, ht_cap->ht_sgi_40,
|
|
|
+ ht_cap->num_rf_chains);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * wma_derive_ext_vht_cap() - Derive VHT caps based on given value
|
|
|
+ * @wma_handle: pointer to wma_handle
|
|
|
+ * @vht_cap: pointer to given VHT caps to be filled
|
|
|
+ * @value: new VHT cap info provided in form of bitmask
|
|
|
+ *
|
|
|
+ * This function takes the value provided in form of bitmask and decodes
|
|
|
+ * it. After decoding, what ever value it gets, it takes the union(max) or
|
|
|
+ * intersection(min) with previously derived values.
|
|
|
+ *
|
|
|
+ * Return: none
|
|
|
+ *
|
|
|
+ */
|
|
|
+static void wma_derive_ext_vht_cap(t_wma_handle *wma_handle,
|
|
|
+ struct wma_tgt_vht_cap *vht_cap, uint32_t value)
|
|
|
+{
|
|
|
+ struct wma_tgt_vht_cap tmp_cap = {0};
|
|
|
+ uint32_t tmp = 0;
|
|
|
+
|
|
|
+ if (NULL == wma_handle || NULL == vht_cap)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (0 == qdf_mem_cmp(vht_cap, &tmp_cap,
|
|
|
+ sizeof(struct wma_tgt_vht_cap))) {
|
|
|
+ if (value & WMI_VHT_CAP_MAX_MPDU_LEN_11454)
|
|
|
+ vht_cap->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_11454;
|
|
|
+ else if (value & WMI_VHT_CAP_MAX_MPDU_LEN_7935)
|
|
|
+ vht_cap->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_7935;
|
|
|
+ else
|
|
|
+ vht_cap->vht_max_mpdu = 0;
|
|
|
+
|
|
|
+ if (value & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ) {
|
|
|
+ vht_cap->supp_chan_width =
|
|
|
+ 1 << eHT_CHANNEL_WIDTH_80P80MHZ;
|
|
|
+ vht_cap->supp_chan_width |=
|
|
|
+ 1 << eHT_CHANNEL_WIDTH_160MHZ;
|
|
|
+ } else if (value & WMI_VHT_CAP_CH_WIDTH_160MHZ) {
|
|
|
+ vht_cap->supp_chan_width =
|
|
|
+ 1 << eHT_CHANNEL_WIDTH_160MHZ;
|
|
|
+ } else {
|
|
|
+ vht_cap->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80MHZ;
|
|
|
+ }
|
|
|
+ vht_cap->vht_rx_ldpc = value & WMI_VHT_CAP_RX_LDPC;
|
|
|
+ vht_cap->vht_short_gi_80 = value & WMI_VHT_CAP_SGI_80MHZ;
|
|
|
+ vht_cap->vht_short_gi_160 = value & WMI_VHT_CAP_SGI_160MHZ;
|
|
|
+ vht_cap->vht_tx_stbc = value & WMI_VHT_CAP_TX_STBC;
|
|
|
+ vht_cap->vht_rx_stbc =
|
|
|
+ (value & WMI_VHT_CAP_RX_STBC_1SS) |
|
|
|
+ (value & WMI_VHT_CAP_RX_STBC_2SS) |
|
|
|
+ (value & WMI_VHT_CAP_RX_STBC_3SS);
|
|
|
+ vht_cap->vht_max_ampdu_len_exp =
|
|
|
+ (value & WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) >>
|
|
|
+ WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT;
|
|
|
+ vht_cap->vht_su_bformer = value & WMI_VHT_CAP_SU_BFORMER;
|
|
|
+ vht_cap->vht_su_bformee = value & WMI_VHT_CAP_SU_BFORMEE;
|
|
|
+ vht_cap->vht_mu_bformer = value & WMI_VHT_CAP_MU_BFORMER;
|
|
|
+ vht_cap->vht_mu_bformee = value & WMI_VHT_CAP_MU_BFORMEE;
|
|
|
+ vht_cap->vht_txop_ps = value & WMI_VHT_CAP_TXOP_PS;
|
|
|
+ } else {
|
|
|
+ if (value & WMI_VHT_CAP_MAX_MPDU_LEN_11454)
|
|
|
+ tmp = WMI_VHT_CAP_MAX_MPDU_LEN_11454;
|
|
|
+ else if (value & WMI_VHT_CAP_MAX_MPDU_LEN_7935)
|
|
|
+ tmp = WMI_VHT_CAP_MAX_MPDU_LEN_7935;
|
|
|
+ else
|
|
|
+ tmp = 0;
|
|
|
+ vht_cap->vht_max_mpdu = QDF_MIN(vht_cap->vht_max_mpdu, tmp);
|
|
|
+
|
|
|
+ if ((value & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ)) {
|
|
|
+ tmp = (1 << eHT_CHANNEL_WIDTH_80P80MHZ) |
|
|
|
+ (1 << eHT_CHANNEL_WIDTH_160MHZ);
|
|
|
+ } else if (value & WMI_VHT_CAP_CH_WIDTH_160MHZ) {
|
|
|
+ tmp = 1 << eHT_CHANNEL_WIDTH_160MHZ;
|
|
|
+ } else {
|
|
|
+ tmp = 1 << eHT_CHANNEL_WIDTH_80MHZ;
|
|
|
+ }
|
|
|
+ vht_cap->supp_chan_width =
|
|
|
+ QDF_MAX(vht_cap->supp_chan_width, tmp);
|
|
|
+ vht_cap->vht_rx_ldpc = QDF_MIN(vht_cap->vht_rx_ldpc,
|
|
|
+ value & WMI_VHT_CAP_RX_LDPC);
|
|
|
+ vht_cap->vht_short_gi_80 = QDF_MAX(vht_cap->vht_short_gi_80,
|
|
|
+ value & WMI_VHT_CAP_SGI_80MHZ);
|
|
|
+ vht_cap->vht_short_gi_160 = QDF_MAX(vht_cap->vht_short_gi_160,
|
|
|
+ value & WMI_VHT_CAP_SGI_160MHZ);
|
|
|
+ vht_cap->vht_tx_stbc = QDF_MAX(vht_cap->vht_tx_stbc,
|
|
|
+ value & WMI_VHT_CAP_TX_STBC);
|
|
|
+ vht_cap->vht_rx_stbc = QDF_MIN(vht_cap->vht_rx_stbc,
|
|
|
+ (value & WMI_VHT_CAP_RX_STBC_1SS) |
|
|
|
+ (value & WMI_VHT_CAP_RX_STBC_2SS) |
|
|
|
+ (value & WMI_VHT_CAP_RX_STBC_3SS));
|
|
|
+ vht_cap->vht_max_ampdu_len_exp =
|
|
|
+ QDF_MIN(vht_cap->vht_max_ampdu_len_exp,
|
|
|
+ (value & WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) >>
|
|
|
+ WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT);
|
|
|
+ vht_cap->vht_su_bformer = QDF_MAX(vht_cap->vht_su_bformer,
|
|
|
+ value & WMI_VHT_CAP_SU_BFORMER);
|
|
|
+ vht_cap->vht_su_bformee = QDF_MAX(vht_cap->vht_su_bformee,
|
|
|
+ value & WMI_VHT_CAP_SU_BFORMEE);
|
|
|
+ vht_cap->vht_mu_bformer = QDF_MAX(vht_cap->vht_mu_bformer,
|
|
|
+ value & WMI_VHT_CAP_MU_BFORMER);
|
|
|
+ vht_cap->vht_mu_bformee = QDF_MAX(vht_cap->vht_mu_bformee,
|
|
|
+ value & WMI_VHT_CAP_MU_BFORMEE);
|
|
|
+ vht_cap->vht_txop_ps = QDF_MIN(vht_cap->vht_txop_ps,
|
|
|
+ value & WMI_VHT_CAP_TXOP_PS);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * wma_update_target_ext_vht_cap() - Update VHT caps with given extended cap
|
|
|
+ * @wma_handle: pointer to wma_handle
|
|
|
+ * @vht_cap: VHT cap structure to be filled
|
|
|
+ *
|
|
|
+ * This function loop through each hardware mode and for each hardware mode
|
|
|
+ * again it loop through each MAC/PHY and pull the caps 2G and 5G specific
|
|
|
+ * VHT caps and derives the final cap.
|
|
|
+ *
|
|
|
+ * Return: none
|
|
|
+ *
|
|
|
+ */
|
|
|
+static void wma_update_target_ext_vht_cap(t_wma_handle *wma_handle,
|
|
|
+ struct wma_tgt_vht_cap *vht_cap)
|
|
|
+{
|
|
|
+ int i, j = 0, max_mac;
|
|
|
+ uint32_t vht_cap_info_2g, vht_cap_info_5g;
|
|
|
+ struct wma_tgt_vht_cap tmp_vht_cap = {0}, tmp_cap = {0};
|
|
|
+ struct extended_caps *phy_caps;
|
|
|
+ WMI_MAC_PHY_CAPABILITIES *mac_cap;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * for legacy device extended cap might not even come, so in that case
|
|
|
+ * don't overwrite legacy values
|
|
|
+ */
|
|
|
+ if (!wma_handle ||
|
|
|
+ (0 == wma_handle->phy_caps.num_hw_modes.num_hw_modes)) {
|
|
|
+ WMA_LOGI("%s: No extended VHT cap for current SOC", __func__);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ phy_caps = &wma_handle->phy_caps;
|
|
|
+ for (i = 0; i < phy_caps->num_hw_modes.num_hw_modes; i++) {
|
|
|
+ if (phy_caps->each_hw_mode_cap[i].phy_id_map == PHY1_PHY2)
|
|
|
+ max_mac = j + 2;
|
|
|
+ else
|
|
|
+ max_mac = j + 1;
|
|
|
+ for ( ; j < max_mac; j++) {
|
|
|
+ mac_cap = &phy_caps->each_phy_cap_per_hwmode[j];
|
|
|
+ vht_cap_info_2g = mac_cap->vht_cap_info_2G;
|
|
|
+ vht_cap_info_5g = mac_cap->vht_cap_info_5G;
|
|
|
+ if (vht_cap_info_2g)
|
|
|
+ wma_derive_ext_vht_cap(wma_handle, &tmp_vht_cap,
|
|
|
+ vht_cap_info_2g);
|
|
|
+ if (vht_cap_info_5g)
|
|
|
+ wma_derive_ext_vht_cap(wma_handle, &tmp_vht_cap,
|
|
|
+ vht_cap_info_5g);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (0 != qdf_mem_cmp(&tmp_cap, &tmp_vht_cap,
|
|
|
+ sizeof(struct wma_tgt_vht_cap))) {
|
|
|
+ qdf_mem_copy(vht_cap, &tmp_vht_cap,
|
|
|
+ sizeof(struct wma_tgt_vht_cap));
|
|
|
+ }
|
|
|
+
|
|
|
+ WMA_LOGI("%s: [ext vhtcap] max_mpdu %d supp_chan_width %x rx_ldpc %x\n \
|
|
|
+ short_gi_80 %x tx_stbc %x rx_stbc %x txop_ps %x\n \
|
|
|
+ su_bformee %x mu_bformee %x max_ampdu_len_exp %d", __func__,
|
|
|
+ vht_cap->vht_max_mpdu, vht_cap->supp_chan_width,
|
|
|
+ vht_cap->vht_rx_ldpc, vht_cap->vht_short_gi_80,
|
|
|
+ vht_cap->vht_tx_stbc, vht_cap->vht_rx_stbc,
|
|
|
+ vht_cap->vht_txop_ps, vht_cap->vht_su_bformee,
|
|
|
+ vht_cap->vht_mu_bformee, vht_cap->vht_max_ampdu_len_exp);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* wma_update_hdd_cfg() - update HDD config
|
|
|
* @wma_handle: wma handle
|
|
@@ -3557,6 +3852,12 @@ static void wma_update_hdd_cfg(tp_wma_handle wma_handle)
|
|
|
wma_update_target_services(wma_handle, &tgt_cfg.services);
|
|
|
wma_update_target_ht_cap(wma_handle, &tgt_cfg.ht_cap);
|
|
|
wma_update_target_vht_cap(wma_handle, &tgt_cfg.vht_cap);
|
|
|
+ /*
|
|
|
+ * This will overwrite the structure filled by wma_update_target_ht_cap
|
|
|
+ * and wma_update_target_vht_cap APIs.
|
|
|
+ */
|
|
|
+ wma_update_target_ext_ht_cap(wma_handle, &tgt_cfg.ht_cap);
|
|
|
+ wma_update_target_ext_vht_cap(wma_handle, &tgt_cfg.vht_cap);
|
|
|
|
|
|
tgt_cfg.target_fw_version = wma_handle->target_fw_version;
|
|
|
#ifdef WLAN_FEATURE_LPSS
|