qcacld-3.0: Add support for dynamic chains update in set antenna mode ioctl

Populate and verify the num of chains params sent by
the user and then send it to the fw.

Change-Id: I9a4870913ce9484d1a5dc5fddcade72bdafb6116
CRs-Fixed: 2347501
diff --git a/core/hdd/src/wlan_hdd_ioctl.c b/core/hdd/src/wlan_hdd_ioctl.c
index 96e976a..a4bf3a1 100644
--- a/core/hdd/src/wlan_hdd_ioctl.c
+++ b/core/hdd/src/wlan_hdd_ioctl.c
@@ -6651,10 +6651,76 @@
 	osif_request_put(request);
 }
 
+static QDF_STATUS
+hdd_populate_vdev_chains(struct wlan_mlme_nss_chains *nss_chains_cfg,
+			 uint8_t tx_chains,
+			 uint8_t rx_chains,
+			 enum nss_chains_band_info band,
+			 struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+
+	nss_chains_cfg->num_rx_chains[band] = rx_chains;
+	nss_chains_cfg->num_tx_chains[band] = tx_chains;
+
+	dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+	if (!dynamic_cfg) {
+		hdd_err("nss chain dynamic config NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	/*
+	 * If user gives any nss value, then chains will be adjusted based on
+	 * nss (in SME func sme_validate_user_nss_chain_params).
+	 * If Chains are not suitable as per current NSS then, we need to
+	 * return, and the below logic is added for the same.
+	 */
+
+	if ((dynamic_cfg->rx_nss[band] > rx_chains) ||
+	    (dynamic_cfg->tx_nss[band] > tx_chains)) {
+		hdd_err("Chains less than nss, configure correct nss first.");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static int
+hdd_set_dynamic_antenna_mode(struct hdd_adapter *adapter,
+			     uint8_t num_rx_chains,
+			     uint8_t num_tx_chains)
+{
+	enum nss_chains_band_info band;
+	struct wlan_mlme_nss_chains user_cfg;
+	QDF_STATUS status;
+	mac_handle_t mac_handle;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+
+	mac_handle = hdd_ctx->mac_handle;
+	if (!mac_handle) {
+		hdd_err("NULL MAC handle");
+		return -EINVAL;
+	}
+
+	qdf_mem_zero(&user_cfg, sizeof(user_cfg));
+	for (band = BAND_2GHZ; band < BAND_MAX; band++) {
+		status = hdd_populate_vdev_chains(&user_cfg,
+						  num_rx_chains,
+						  num_tx_chains, band,
+						  adapter->vdev);
+		if (QDF_IS_STATUS_ERROR(status))
+			return -EINVAL;
+	}
+	status = sme_nss_chains_update(mac_handle,
+				       &user_cfg,
+				       adapter->session_id);
+	if (QDF_IS_STATUS_ERROR(status))
+		return -EINVAL;
+
+	return 0;
+}
 int hdd_set_antenna_mode(struct hdd_adapter *adapter,
 				  struct hdd_context *hdd_ctx, int mode)
 {
-
 	struct sir_antenna_mode_param params;
 	QDF_STATUS status;
 	int ret = 0;
@@ -6697,6 +6763,12 @@
 		goto exit;
 	}
 
+	if (hdd_ctx->dynamic_nss_chains_support) {
+		return hdd_set_dynamic_antenna_mode(adapter,
+						    params.num_rx_chains,
+						    params.num_tx_chains);
+	}
+
 	/* Check TDLS status and update antenna mode */
 	if ((QDF_STA_MODE == adapter->device_mode) &&
 	    policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) {