qcacld-3.0: Validate nss configuration from user
Validate the nss set by the user and then
send the user config to the firmware
Change-Id: Ia1292e428e0c5b30ff0b96f2387ea29ceec9c97c
CRs-Fixed: 2347502
diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c
index 009f0a9..66c25df 100644
--- a/core/hdd/src/wlan_hdd_cfg.c
+++ b/core/hdd/src/wlan_hdd_cfg.c
@@ -4342,6 +4342,16 @@
CFG_PMKID_MODES_PMKSA_CACHING) ? 1 : 0;
}
+static void
+hdd_populate_vdev_nss(struct wlan_mlme_nss_chains *user_cfg,
+ uint8_t tx_nss,
+ uint8_t rx_nss,
+ enum nss_chains_band_info band)
+{
+ user_cfg->rx_nss[band] = rx_nss;
+ user_cfg->tx_nss[band] = tx_nss;
+}
+
/**
* hdd_update_nss() - Update the number of spatial streams supported.
* Ensure that nss is either 1 or 2 before calling this.
@@ -4368,12 +4378,50 @@
uint8_t enable2x2;
mac_handle_t mac_handle;
bool bval = 0;
+ enum nss_chains_band_info band;
+ struct wlan_mlme_nss_chains user_cfg;
+ uint8_t tx_nss, rx_nss;
if ((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);
+ return QDF_STATUS_E_INVAL;
+ }
+
+ mac_handle = hdd_ctx->mac_handle;
+ if (!mac_handle) {
+ hdd_err("NULL MAC handle");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ /* Till now we dont have support for different rx, tx nss values */
+ tx_nss = nss;
+ rx_nss = nss;
+
+ qdf_mem_zero(&user_cfg, sizeof(user_cfg));
+
+ if (hdd_ctx->dynamic_nss_chains_support) {
+ for (band = BAND_2GHZ; band < BAND_MAX; band++)
+ hdd_populate_vdev_nss(&user_cfg, tx_nss,
+ rx_nss, band);
+ if (QDF_IS_STATUS_ERROR(
+ sme_nss_chains_update(mac_handle,
+ &user_cfg,
+ adapter->session_id)))
+ return QDF_STATUS_E_FAILURE;
+
+ return QDF_STATUS_SUCCESS;
+ }
+
+ /*
+ * The code below is executed only when fw doesn't support dynamic
+ * update of nss and chains per vdev feature, for the upcoming
+ * connection
+ */
enable2x2 = (nss == 1) ? 0 : 1;
qdf_status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
@@ -4387,12 +4435,6 @@
return QDF_STATUS_SUCCESS;
}
- mac_handle = hdd_ctx->mac_handle;
- if (!mac_handle) {
- hdd_err("NULL MAC handle");
- return QDF_STATUS_E_INVAL;
- }
-
if (sme_is_any_session_in_connected_state(mac_handle)) {
hdd_err("Connected sessions present, Do not change NSS");
return QDF_STATUS_E_INVAL;
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index d76d87f1..393ab49 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -342,6 +342,23 @@
uint8_t rf_chains_supported);
/**
+ * sme_nss_chains_update() - validate and send the user params to fw
+ * @mac_handle: The handle returned by mac_open.
+ * @user_cfg: pointer to the structure to be validated and sent to fw
+ * @vdev_id: vdev id
+ *
+ *
+ * This API will validate the config, and if found correct will update the
+ * config in dynamic config, and send to the fw.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+sme_nss_chains_update(mac_handle_t mac_handle,
+ struct wlan_mlme_nss_chains *user_cfg,
+ uint8_t vdev_id);
+
+/**
* sme_open_session() - Open a session for given persona
*
* This is a synchronous API. For any protocol stack related activity
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index 30560f0..d033b78 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -4880,6 +4880,198 @@
rf_chains_supported);
}
+static void
+sme_populate_user_config(struct wlan_mlme_nss_chains *dynamic_cfg,
+ struct wlan_mlme_nss_chains *user_cfg,
+ enum nss_chains_band_info band)
+{
+ if (!user_cfg->num_rx_chains[band])
+ user_cfg->num_rx_chains[band] =
+ dynamic_cfg->num_rx_chains[band];
+
+ if (!user_cfg->num_tx_chains[band])
+ user_cfg->num_tx_chains[band] =
+ dynamic_cfg->num_tx_chains[band];
+
+ if (!user_cfg->rx_nss[band])
+ user_cfg->rx_nss[band] =
+ dynamic_cfg->rx_nss[band];
+
+ if (!user_cfg->tx_nss[band])
+ user_cfg->tx_nss[band] =
+ dynamic_cfg->tx_nss[band];
+
+ if (!user_cfg->num_tx_chains_11a)
+ user_cfg->num_tx_chains_11a =
+ dynamic_cfg->num_tx_chains_11a;
+
+ if (!user_cfg->num_tx_chains_11b)
+ user_cfg->num_tx_chains_11b =
+ dynamic_cfg->num_tx_chains_11b;
+
+ if (!user_cfg->num_tx_chains_11g)
+ user_cfg->num_tx_chains_11g =
+ dynamic_cfg->num_tx_chains_11g;
+
+ if (!user_cfg->disable_rx_mrc[band])
+ user_cfg->disable_rx_mrc[band] =
+ dynamic_cfg->disable_rx_mrc[band];
+
+ if (!user_cfg->disable_tx_mrc[band])
+ user_cfg->disable_tx_mrc[band] =
+ dynamic_cfg->disable_tx_mrc[band];
+}
+
+static QDF_STATUS
+sme_validate_from_ini_config(struct wlan_mlme_nss_chains *user_cfg,
+ struct wlan_mlme_nss_chains *ini_cfg,
+ enum nss_chains_band_info band)
+{
+ if (user_cfg->num_rx_chains[band] >
+ ini_cfg->num_rx_chains[band])
+ return QDF_STATUS_E_FAILURE;
+
+ if (user_cfg->num_tx_chains[band] >
+ ini_cfg->num_tx_chains[band])
+ return QDF_STATUS_E_FAILURE;
+
+ if (user_cfg->rx_nss[band] >
+ ini_cfg->rx_nss[band])
+ return QDF_STATUS_E_FAILURE;
+
+ if (user_cfg->tx_nss[band] >
+ ini_cfg->tx_nss[band])
+ return QDF_STATUS_E_FAILURE;
+
+ if (user_cfg->num_tx_chains_11a >
+ ini_cfg->num_tx_chains_11a)
+ return QDF_STATUS_E_FAILURE;
+
+ if (user_cfg->num_tx_chains_11b >
+ ini_cfg->num_tx_chains_11b)
+ return QDF_STATUS_E_FAILURE;
+
+ if (user_cfg->num_tx_chains_11g >
+ ini_cfg->num_tx_chains_11g)
+ return QDF_STATUS_E_FAILURE;
+
+ return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+sme_validate_user_nss_chain_params(
+ struct wlan_mlme_nss_chains *user_cfg,
+ enum nss_chains_band_info band)
+{
+ /* Reject as 2x1 modes are not supported in chains yet */
+
+ if (user_cfg->num_tx_chains[band] >
+ user_cfg->num_rx_chains[band])
+ return QDF_STATUS_E_FAILURE;
+
+ /* Also if mode is 2x2, we cant have chains as 1x1, or 1x2, or 2x1 */
+
+ if (user_cfg->tx_nss[band] >
+ user_cfg->num_tx_chains[band])
+ user_cfg->num_tx_chains[band] =
+ user_cfg->tx_nss[band];
+
+ if (user_cfg->rx_nss[band] >
+ user_cfg->num_rx_chains[band])
+ user_cfg->num_rx_chains[band] =
+ user_cfg->rx_nss[band];
+
+ /*
+ * It may happen that already chains are in 1x1 mode and nss too
+ * is in 1x1 mode, but the tx 11a/b/g chains in user config comes
+ * as 2x1, or 1x2 which cannot support respective mode, as tx chains
+ * for respective band have max of 1x1 only, so these cannot exceed
+ * respective band num tx chains.
+ */
+
+ if (user_cfg->num_tx_chains_11a >
+ user_cfg->num_tx_chains[BAND_5GHZ])
+ user_cfg->num_tx_chains_11a =
+ user_cfg->num_tx_chains[BAND_5GHZ];
+
+ if (user_cfg->num_tx_chains_11b >
+ user_cfg->num_tx_chains[BAND_2GHZ])
+ user_cfg->num_tx_chains_11b =
+ user_cfg->num_tx_chains[BAND_2GHZ];
+
+ if (user_cfg->num_tx_chains_11g >
+ user_cfg->num_tx_chains[BAND_2GHZ])
+ user_cfg->num_tx_chains_11g =
+ user_cfg->num_tx_chains[BAND_2GHZ];
+
+ return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+sme_validate_nss_chains_config(struct wlan_objmgr_vdev *vdev,
+ struct wlan_mlme_nss_chains *user_cfg)
+{
+ enum nss_chains_band_info band;
+ struct wlan_mlme_nss_chains *ini_cfg;
+ struct wlan_mlme_nss_chains *dynamic_cfg;
+ QDF_STATUS status;
+
+ ini_cfg = mlme_get_ini_vdev_config(vdev);
+ if (!ini_cfg) {
+ sme_err("nss chain ini config NULL");
+ return QDF_STATUS_E_FAILURE;
+ }
+ dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+ if (!dynamic_cfg) {
+ sme_err("nss chain dynamic config NULL");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ for (band = BAND_2GHZ; band < BAND_MAX; band++) {
+ sme_populate_user_config(dynamic_cfg,
+ user_cfg, band);
+ status = sme_validate_from_ini_config(user_cfg,
+ ini_cfg,
+ band);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ sme_err("Validation from ini config failed");
+ return QDF_STATUS_E_FAILURE;
+ }
+ status = sme_validate_user_nss_chain_params(user_cfg,
+ band);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ sme_err("User cfg validation failed");
+ return QDF_STATUS_E_FAILURE;
+ }
+ }
+
+ return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+sme_nss_chains_update(mac_handle_t mac_handle,
+ struct wlan_mlme_nss_chains *user_cfg,
+ uint8_t vdev_id)
+{
+ struct sAniSirGlobal *mac_ctx = MAC_CONTEXT(mac_handle);
+ QDF_STATUS status;
+ struct wlan_objmgr_vdev *vdev =
+ wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc,
+ vdev_id,
+ WLAN_LEGACY_SME_ID);
+ if (!vdev) {
+ sme_err("Got NULL vdev obj, returning");
+ return QDF_STATUS_E_FAILURE;
+ }
+ status = sme_validate_nss_chains_config(vdev, user_cfg);
+ if (QDF_IS_STATUS_ERROR(status))
+ goto end;
+
+end:
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID);
+ return status;
+}
+
QDF_STATUS sme_open_session(mac_handle_t hal, struct sme_session_params *params)
{
QDF_STATUS status = QDF_STATUS_E_INVAL;