diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h index 3790cab4c8..ed868c5e4c 100644 --- a/core/hdd/inc/wlan_hdd_cfg.h +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -318,7 +318,8 @@ void hdd_cfg_print_global_config(struct hdd_context *hdd_ctx); * hdd_update_nss() - Update the number of spatial streams supported. * * @adapter: the pointer to adapter - * @nss: the number of spatial streams to be updated + * @tx_nss: the number of Tx spatial streams to be updated + * @rx_nss: the number of Rx spatial streams to be updated * * This function is used to modify the number of spatial streams * supported when not in connected state. @@ -326,7 +327,8 @@ void hdd_cfg_print_global_config(struct hdd_context *hdd_ctx); * Return: QDF_STATUS_SUCCESS if nss is correctly updated, * otherwise QDF_STATUS_E_FAILURE would be returned */ -QDF_STATUS hdd_update_nss(struct hdd_adapter *adapter, uint8_t nss); +QDF_STATUS hdd_update_nss(struct hdd_adapter *adapter, uint8_t tx_nss, + uint8_t rx_nss); /** * hdd_get_nss() - Get the number of spatial streams supported by the adapter diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c index 5657baa554..aacbe34daa 100644 --- a/core/hdd/src/wlan_hdd_cfg.c +++ b/core/hdd/src/wlan_hdd_cfg.c @@ -1063,7 +1063,8 @@ hdd_set_nss_params(struct hdd_adapter *adapter, return QDF_STATUS_SUCCESS; } -QDF_STATUS hdd_update_nss(struct hdd_adapter *adapter, uint8_t nss) +QDF_STATUS hdd_update_nss(struct hdd_adapter *adapter, uint8_t tx_nss, + uint8_t rx_nss) { struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); uint32_t rx_supp_data_rate, tx_supp_data_rate; @@ -1076,16 +1077,16 @@ QDF_STATUS hdd_update_nss(struct hdd_adapter *adapter, uint8_t nss) uint8_t enable2x2; mac_handle_t mac_handle; bool bval = 0; - uint8_t tx_nss, rx_nss; uint8_t band, max_supp_nss; - if ((nss == 2) && (hdd_ctx->num_rf_chains != 2)) { + if ((tx_nss == 2 || rx_nss == 2) && (hdd_ctx->num_rf_chains != 2)) { hdd_err("No support for 2 spatial streams"); return QDF_STATUS_E_INVAL; } - if (nss > MAX_VDEV_NSS) { - hdd_debug("Cannot support %d nss streams", nss); + if (tx_nss > MAX_VDEV_NSS || rx_nss > MAX_VDEV_NSS) { + hdd_debug("Cannot support tx_nss: %d rx_nss: %d", tx_nss, + rx_nss); return QDF_STATUS_E_INVAL; } @@ -1102,10 +1103,6 @@ QDF_STATUS hdd_update_nss(struct hdd_adapter *adapter, uint8_t nss) } max_supp_nss = MAX_VDEV_NSS; - /* Till now we dont have support for different rx, tx nss values */ - tx_nss = nss; - rx_nss = nss; - /* * If FW is supporting the dynamic nss update, this command is meant to * be per vdev, so update only the ini params of that particular vdev @@ -1147,7 +1144,7 @@ QDF_STATUS hdd_update_nss(struct hdd_adapter *adapter, uint8_t nss) * update of nss and chains per vdev feature, for the upcoming * connection */ - enable2x2 = (nss == 1) ? 0 : 1; + enable2x2 = (rx_nss == 2) ? 1 : 0; if (bval == enable2x2) { hdd_debug("NSS same as requested"); @@ -1165,14 +1162,18 @@ QDF_STATUS hdd_update_nss(struct hdd_adapter *adapter, uint8_t nss) return QDF_STATUS_E_FAILURE; } - if (!enable2x2) { - /* 1x1 */ - rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + if (tx_nss == 1 && rx_nss == 2) { + /* 1x2 */ + rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2; tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; - } else { + } else if (enable2x2) { /* 2x2 */ rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2; tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + } else { + /* 1x1 */ + rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; } /* Update Rx Highest Long GI data Rate */ @@ -1228,7 +1229,7 @@ skip_ht_cap_update: if (QDF_IS_STATUS_SUCCESS(qdf_status)) { mcs_set[0] = mcs_set_temp[0]; if (enable2x2) - for (val_len = 0; val_len < nss; val_len++) + for (val_len = 0; val_len < rx_nss; val_len++) mcs_set[val_len] = WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES; if (ucfg_mlme_set_supported_mcs_set( @@ -1242,10 +1243,10 @@ skip_ht_cap_update: status = false; hdd_err("Could not get MCS SET from CFG"); } - sme_update_he_cap_nss(mac_handle, adapter->vdev_id, nss); + sme_update_he_cap_nss(mac_handle, adapter->vdev_id, rx_nss); #undef WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES - if (QDF_STATUS_SUCCESS != sme_update_nss(mac_handle, nss)) + if (QDF_STATUS_SUCCESS != sme_update_nss(mac_handle, rx_nss)) status = false; hdd_set_policy_mgr_user_cfg(hdd_ctx); diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 4b8d6fccb2..ab07436cd9 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -6979,6 +6979,8 @@ const struct nla_policy wlan_hdd_wifi_config_policy[ [QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS] = {.type = NLA_U8 }, [QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_SETTING] = {.type = NLA_U8 }, [QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_LEVEL] = {.type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS] = {.type = NLA_U8 }, }; @@ -7697,6 +7699,37 @@ static int hdd_config_vdev_chains(struct hdd_adapter *adapter, return 0; } +static int hdd_config_tx_rx_nss(struct hdd_adapter *adapter, + struct nlattr *tb[]) +{ + uint8_t tx_nss, rx_nss; + QDF_STATUS status; + + struct nlattr *tx_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS]; + struct nlattr *rx_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS]; + + if (!tx_attr && !rx_attr) + return 0; + + tx_nss = nla_get_u8(tx_attr); + rx_nss = nla_get_u8(rx_attr); + hdd_debug("tx_nss %d rx_nss %d", tx_nss, rx_nss); + /* Only allow NSS for tx_rx_nss for 1x1, 1x2, 2x2 */ + if (!((tx_nss == 1 && rx_nss == 2) || (tx_nss == 1 && rx_nss == 1) || + (tx_nss == 2 && rx_nss == 2))) { + hdd_err("Setting tx_nss %d rx_nss %d not allowed", tx_nss, + rx_nss); + return 0; + } + status = hdd_update_nss(adapter, tx_nss, rx_nss); + if (status != QDF_STATUS_SUCCESS) + hdd_debug("Can't set tx_nss %d rx_nss %d", tx_nss, rx_nss); + + return 0; +} + static int hdd_config_ani(struct hdd_adapter *adapter, struct nlattr *tb[]) { @@ -8740,7 +8773,7 @@ static int hdd_set_nss(struct hdd_adapter *adapter, nss = nla_get_u8(attr); - status = hdd_update_nss(adapter, nss); + status = hdd_update_nss(adapter, nss, nss); ret = qdf_status_to_os_return(status); if (ret == 0 && adapter->device_mode == QDF_SAP_MODE) @@ -9458,6 +9491,7 @@ static const interdependent_setter_fn interdependent_setters[] = { hdd_config_msdu_aggregation, hdd_config_vdev_chains, hdd_config_ani, + hdd_config_tx_rx_nss, }; /** diff --git a/core/hdd/src/wlan_hdd_hostapd_wext.c b/core/hdd/src/wlan_hdd_hostapd_wext.c index 06708a28e1..987cc69ab3 100644 --- a/core/hdd/src/wlan_hdd_hostapd_wext.c +++ b/core/hdd/src/wlan_hdd_hostapd_wext.c @@ -899,7 +899,7 @@ static __iw_softap_setparam(struct net_device *dev, case QCASAP_NSS_CMD: { hdd_debug("QCASAP_NSS_CMD val %d", set_value); - hdd_update_nss(adapter, set_value); + hdd_update_nss(adapter, set_value, set_value); ret = wma_cli_set_command(adapter->vdev_id, WMI_VDEV_PARAM_NSS, set_value, VDEV_CMD); diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index 4b36036a22..f1a09d5ad6 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -3918,7 +3918,7 @@ static int hdd_we_set_nss(struct hdd_adapter *adapter, int nss) return -EINVAL; } - status = hdd_update_nss(adapter, nss); + status = hdd_update_nss(adapter, nss, nss); if (QDF_IS_STATUS_ERROR(status)) hdd_err("cfg set failed, value %d status %d", nss, status); diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 7d91854bb1..9eda355cf5 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -11270,7 +11270,8 @@ void sme_update_he_cap_nss(mac_handle_t mac_handle, uint8_t session_id, uint32_t mcs_map = 0; if (!nss || (nss > 2)) { - sme_err("invalid Nss value %d", nss); + sme_err("invalid Nss value nss %d", nss); + return; } csr_session = CSR_GET_SESSION(mac_ctx, session_id); if (!csr_session) {