瀏覽代碼

qcacld-3.0: Add support to get num tx/rx chains

Add support to get num tx and rx chains.

Change-Id: Iae8e3d15679e5e9ca139c59e6880a5d733ee17ef
CRs-Fixed: 3596086
Vinod Kumar Myadam 1 年之前
父節點
當前提交
bca37ddeea

+ 28 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -1682,6 +1682,20 @@ wlan_set_tpc_update_required_for_sta(struct wlan_objmgr_vdev *vdev, bool value)
 }
 #endif
 
+/**
+ * wlan_mlme_get_sta_num_tx_chains() - API to get station num tx chains
+ *
+ * @psoc: psoc context
+ * @vdev: pointer to vdev
+ * @tx_chains : tx_chains out parameter
+ *
+ * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE
+ */
+QDF_STATUS
+wlan_mlme_get_sta_num_tx_chains(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t *tx_chains);
+
 /**
  * wlan_mlme_get_sta_tx_nss() - API to get station tx NSS
  *
@@ -1696,6 +1710,20 @@ wlan_mlme_get_sta_tx_nss(struct wlan_objmgr_psoc *psoc,
 			 struct wlan_objmgr_vdev *vdev,
 			 uint8_t *tx_nss);
 
+/**
+ * wlan_mlme_get_sta_num_rx_chains() - API to get station num rx chains
+ *
+ * @psoc: psoc context
+ * @vdev: pointer to vdev
+ * @rx_chains : rx_chains out parameter
+ *
+ * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE
+ */
+QDF_STATUS
+wlan_mlme_get_sta_num_rx_chains(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t *rx_chains);
+
 /**
  * wlan_mlme_get_sta_rx_nss() - API to get station rx NSS
  *

+ 102 - 0
components/mlme/core/src/wlan_mlme_main.c

@@ -36,6 +36,7 @@
 #include "twt/core/src/wlan_twt_cfg.h"
 #include "wlan_scan_api.h"
 #include "wlan_mlme_vdev_mgr_interface.h"
+#include "wlan_vdev_mgr_utils_api.h"
 
 #define NUM_OF_SOUNDING_DIMENSIONS     1 /*Nss - 1, (Nss = 2 for 2x2)*/
 
@@ -5136,6 +5137,57 @@ wlan_set_tpc_update_required_for_sta(struct wlan_objmgr_vdev *vdev, bool value)
 }
 #endif
 
+QDF_STATUS wlan_mlme_get_sta_num_tx_chains(struct wlan_objmgr_psoc *psoc,
+					   struct wlan_objmgr_vdev *vdev,
+					   uint8_t *tx_chains)
+{
+	bool dynamic_nss_chains_support;
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+	enum band_info operating_band;
+	QDF_STATUS status;
+	struct vdev_mlme_obj *vdev_mlme;
+
+	status = wlan_mlme_cfg_get_dynamic_nss_chains_support
+					(psoc, &dynamic_nss_chains_support);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err("Failed to get dynamic_nss_chains_support");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev_mlme =
+		wlan_objmgr_vdev_get_comp_private_obj(vdev,
+						      WLAN_UMAC_COMP_MLME);
+	if (!vdev_mlme) {
+		QDF_ASSERT(0);
+		return false;
+	}
+
+	if (dynamic_nss_chains_support) {
+		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+		if (!dynamic_cfg) {
+			mlme_err("nss chain dynamic config NULL");
+			return QDF_STATUS_E_INVAL;
+		}
+
+		operating_band = ucfg_cm_get_connected_band(vdev);
+		switch (operating_band) {
+		case BAND_2G:
+			*tx_chains =
+			dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ];
+			break;
+		case BAND_5G:
+			*tx_chains =
+			dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ];
+			break;
+		default:
+			mlme_err("Band %d Not 2G or 5G", operating_band);
+			return QDF_STATUS_E_INVAL;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS wlan_mlme_get_sta_tx_nss(struct wlan_objmgr_psoc *psoc,
 				    struct wlan_objmgr_vdev *vdev,
 				    uint8_t *tx_nss)
@@ -5183,6 +5235,56 @@ QDF_STATUS wlan_mlme_get_sta_tx_nss(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS wlan_mlme_get_sta_num_rx_chains(struct wlan_objmgr_psoc *psoc,
+					   struct wlan_objmgr_vdev *vdev,
+					   uint8_t *rx_chains)
+{
+	bool dynamic_nss_chains_support;
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+	enum band_info operating_band;
+	QDF_STATUS status;
+	struct vdev_mlme_obj *vdev_mlme;
+
+	status = wlan_mlme_cfg_get_dynamic_nss_chains_support
+					(psoc, &dynamic_nss_chains_support);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err("Failed to get dynamic_nss_chains_support");
+		return QDF_STATUS_E_INVAL;
+	}
+	vdev_mlme =
+		wlan_objmgr_vdev_get_comp_private_obj(vdev,
+						      WLAN_UMAC_COMP_MLME);
+	if (!vdev_mlme) {
+		QDF_ASSERT(0);
+		return false;
+	}
+
+	if (dynamic_nss_chains_support) {
+		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+		if (!dynamic_cfg) {
+			mlme_err("nss chain dynamic config NULL");
+			return QDF_STATUS_E_INVAL;
+		}
+
+		operating_band = ucfg_cm_get_connected_band(vdev);
+		switch (operating_band) {
+		case BAND_2G:
+			*rx_chains =
+			dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
+			break;
+		case BAND_5G:
+			*rx_chains =
+			dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ];
+			break;
+		default:
+			mlme_err("Band %d Not 2G or 5G", operating_band);
+			return QDF_STATUS_E_INVAL;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS wlan_mlme_get_sta_rx_nss(struct wlan_objmgr_psoc *psoc,
 				    struct wlan_objmgr_vdev *vdev,
 				    uint8_t *rx_nss)

+ 34 - 0
components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h

@@ -2738,6 +2738,40 @@ ucfg_mlme_update_dynamic_nss_chains_support(struct wlan_objmgr_psoc *psoc,
 	return wlan_mlme_cfg_set_dynamic_nss_chains_support(psoc, val);
 }
 
+/**
+ * ucfg_mlme_get_sta_num_tx_chains() - UCFG API to get station num tx chains
+ *
+ * @psoc: psoc context
+ * @vdev: pointer to vdev
+ * @tx_chains : tx_chains out parameter
+ *
+ * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE
+ */
+static inline QDF_STATUS
+ucfg_mlme_get_sta_num_tx_chains(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t *tx_chains)
+{
+	return wlan_mlme_get_sta_num_tx_chains(psoc, vdev, tx_chains);
+}
+
+/**
+ * ucfg_mlme_get_sta_num_rx_chains() - UCFG API to get station num rx chains
+ *
+ * @psoc: psoc context
+ * @vdev: pointer to vdev
+ * @rx_chains : rx_chains out parameter
+ *
+ * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE
+ */
+static inline QDF_STATUS
+ucfg_mlme_get_sta_num_rx_chains(struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t *rx_chains)
+{
+	return wlan_mlme_get_sta_num_rx_chains(psoc, vdev, rx_chains);
+}
+
 /**
  * ucfg_mlme_get_sta_tx_nss() - UCFG API to get station tx NSS
  *

+ 40 - 0
core/hdd/inc/wlan_hdd_cfg.h

@@ -268,6 +268,19 @@ void hdd_cfg_print_global_config(struct hdd_context *hdd_ctx);
 QDF_STATUS hdd_update_nss(struct wlan_hdd_link_info *link_info,
 			  uint8_t tx_nss, uint8_t rx_nss);
 
+/**
+ * hdd_get_num_chains() - Get the number of chains supported by the adapter
+ *
+ * @adapter: the pointer to adapter
+ * @num_chains: the number of chains supported by the adapter
+ *
+ * This function is used to get the number of chains supported by
+ * the adapter.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_get_num_chains(struct hdd_adapter *adapter, uint8_t *num_chains);
+
 /**
  * hdd_get_nss() - Get the number of spatial streams supported by the adapter
  *
@@ -281,6 +294,20 @@ QDF_STATUS hdd_update_nss(struct wlan_hdd_link_info *link_info,
  */
 QDF_STATUS hdd_get_nss(struct hdd_adapter *adapter, uint8_t *nss);
 
+/**
+ * hdd_get_num_tx_chains() - Get the number of tx chains supported by the
+ * adapter
+ * @link_info: Link info pointer in HDD adapter
+ * @tx_chains: the number of Tx chains supported by the adapter
+ *
+ * This function is used to get the number of Tx chains supported by
+ * the adapter.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_get_num_tx_chains(struct wlan_hdd_link_info *link_info,
+				 uint8_t *tx_chains);
+
 /**
  * hdd_get_tx_nss() - Get the number of spatial streams supported by the adapter
  * @link_info: Link info pointer in HDD adapter
@@ -294,6 +321,19 @@ QDF_STATUS hdd_get_nss(struct hdd_adapter *adapter, uint8_t *nss);
 QDF_STATUS hdd_get_tx_nss(struct wlan_hdd_link_info *link_info,
 			  uint8_t *tx_nss);
 
+/**
+ * hdd_get_num_rx_chains() - Get the number of chains supported by the adapter
+ * @link_info: Link info pointer in HDD adapter
+ * @rx_chains: the number of Rx chains supported by the adapter
+ *
+ * This function is used to get the number of Rx chains supported by
+ * the adapter.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_get_num_rx_chains(struct wlan_hdd_link_info *link_info,
+				 uint8_t *rx_chains);
+
 /**
  * hdd_get_rx_nss() - Get the number of spatial streams supported by the adapter
  * @link_info: Link info pointer in HDD adapter

+ 211 - 0
core/hdd/src/wlan_hdd_cfg.c

@@ -1417,6 +1417,65 @@ QDF_STATUS hdd_get_nss(struct hdd_adapter *adapter, uint8_t *nss)
 	return status;
 }
 
+/**
+ * hdd_get_sap_num_tx_chains() - get the sap num tx chains
+ * @link_info: Pointer of link_info
+ * @tx_chains: pointer to tx_chains
+ *
+ * get the sap num tx chains
+ *
+ * Return: None
+ */
+static QDF_STATUS
+hdd_get_sap_num_tx_chains(struct wlan_hdd_link_info *link_info,
+			  uint8_t *tx_chains)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+	enum band_info operating_band;
+	mac_handle_t mac_handle;
+
+	mac_handle = hdd_ctx->mac_handle;
+	if (!mac_handle) {
+		hdd_debug("NULL MAC handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
+	if (operating_band == BAND_UNKNOWN)
+		return QDF_STATUS_E_INVAL;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	if (hdd_ctx->dynamic_nss_chains_support) {
+		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+		if (!dynamic_cfg) {
+			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+			hdd_debug("nss chain dynamic config NULL");
+			return QDF_STATUS_E_INVAL;
+		}
+		switch (operating_band) {
+		case BAND_2G:
+			*tx_chains =
+			dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ];
+			break;
+		case BAND_5G:
+			*tx_chains =
+			dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ];
+			break;
+		default:
+			hdd_debug("Band %d Not 2G or 5G", operating_band);
+			break;
+		}
+	}
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+	return  QDF_STATUS_SUCCESS;
+}
+
 /**
  * hdd_get_sap_tx_nss() - get the sap tx nss
  * @link_info: Pointer of link_info
@@ -1477,6 +1536,37 @@ hdd_get_sap_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
 	return  QDF_STATUS_SUCCESS;
 }
 
+/**
+ * hdd_get_sta_num_tx_chains() - get the sta num tx chains
+ * @link_info: Pointer of link_info
+ * @tx_chains: pointer to tx_chains
+ *
+ * get the STA num tx chains
+ *
+ * Return: None
+ */
+static QDF_STATUS
+hdd_get_sta_num_tx_chains(struct wlan_hdd_link_info *link_info,
+			  uint8_t *tx_chains)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	status = ucfg_mlme_get_sta_num_tx_chains(hdd_ctx->psoc, vdev,
+						 tx_chains);
+	if (QDF_IS_STATUS_ERROR(status))
+		hdd_err("Failed to get sta_tx_nss");
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+
+	return status;
+}
+
 /**
  * hdd_get_sta_tx_nss() - get the sta tx nss
  * @link_info: Pointer of link_info
@@ -1506,6 +1596,21 @@ hdd_get_sta_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
 	return status;
 }
 
+QDF_STATUS hdd_get_num_tx_chains(struct wlan_hdd_link_info *link_info,
+				 uint8_t *tx_chains)
+{
+	struct hdd_adapter *adapter = link_info->adapter;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (adapter->device_mode == QDF_SAP_MODE ||
+	    adapter->device_mode == QDF_P2P_GO_MODE)
+		status = hdd_get_sap_num_tx_chains(link_info, tx_chains);
+	else
+		status = hdd_get_sta_num_tx_chains(link_info, tx_chains);
+
+	return status;
+}
+
 QDF_STATUS hdd_get_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
 {
 	struct hdd_adapter *adapter = link_info->adapter;
@@ -1520,6 +1625,65 @@ QDF_STATUS hdd_get_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
 	return status;
 }
 
+/**
+ * hdd_get_sap_num_rx_chains() - get the sap num rx chains
+ * @link_info: Pointer to link_info
+ * @rx_chains: pointer to rx_chains
+ *
+ * get the sap num rx chains
+ *
+ * Return: None
+ */
+static QDF_STATUS
+hdd_get_sap_num_rx_chains(struct wlan_hdd_link_info *link_info,
+			  uint8_t *rx_chains)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_mlme_nss_chains *dynamic_cfg;
+	enum band_info operating_band;
+	mac_handle_t mac_handle;
+
+	mac_handle = hdd_ctx->mac_handle;
+	if (!mac_handle) {
+		hdd_debug("NULL MAC handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
+	if (operating_band == BAND_UNKNOWN)
+		return QDF_STATUS_E_INVAL;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	if (hdd_ctx->dynamic_nss_chains_support) {
+		dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+		if (!dynamic_cfg) {
+			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+			hdd_debug("nss chain dynamic config NULL");
+			return QDF_STATUS_E_INVAL;
+		}
+		switch (operating_band) {
+		case BAND_2G:
+			*rx_chains =
+			dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
+			break;
+		case BAND_5G:
+			*rx_chains =
+			dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ];
+			break;
+		default:
+			hdd_debug("Band %d Not 2G or 5G", operating_band);
+			break;
+		}
+	}
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+	return  QDF_STATUS_SUCCESS;
+}
+
 /**
  * hdd_get_sap_rx_nss() - get the sap rx nss
  * @link_info: Pointer to link_info
@@ -1580,6 +1744,38 @@ hdd_get_sap_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
 	return  QDF_STATUS_SUCCESS;
 }
 
+/**
+ * hdd_get_sta_num_rx_chains() - get the sta num rx chains
+ * @link_info: Pointer to link_info in adapter
+ * @rx_chains: pointer to rx_chains
+ *
+ * get the STA num rx chains
+ *
+ * Return: QDF_STATUS_SUCCESS if the RX NSS is returned, otherwise a suitable
+ *         QDF_STATUS_E_* error code
+ */
+static QDF_STATUS
+hdd_get_sta_num_rx_chains(struct wlan_hdd_link_info *link_info,
+			  uint8_t *rx_chains)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
+	if (!vdev)
+		return QDF_STATUS_E_INVAL;
+
+	status = ucfg_mlme_get_sta_num_rx_chains(hdd_ctx->psoc, vdev,
+						 rx_chains);
+	if (QDF_IS_STATUS_ERROR(status))
+		hdd_err("Failed to get sta_rx_nss");
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+
+	return status;
+}
+
 /**
  * hdd_get_sta_rx_nss() - get the sta rx nss
  * @link_info: Pointer to link_info in adapter
@@ -1610,6 +1806,21 @@ hdd_get_sta_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
 	return status;
 }
 
+QDF_STATUS hdd_get_num_rx_chains(struct wlan_hdd_link_info *link_info,
+				 uint8_t *rx_chains)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct hdd_adapter *adapter = link_info->adapter;
+
+	if (adapter->device_mode == QDF_SAP_MODE ||
+	    adapter->device_mode == QDF_P2P_GO_MODE)
+		status = hdd_get_sap_num_rx_chains(link_info, rx_chains);
+	else
+		status = hdd_get_sta_num_rx_chains(link_info, rx_chains);
+
+	return status;
+}
+
 QDF_STATUS hdd_get_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;

+ 81 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -12241,6 +12241,43 @@ static int hdd_get_nss_config(struct wlan_hdd_link_info *link_info,
 	return 0;
 }
 
+/**
+ * hdd_get_num_tx_chains_config() - Get the number of tx chains supported by
+ * the adapter
+ * @link_info: Link info pointer in HDD adapter
+ * @skb: sk buffer to hold nl80211 attributes
+ * @attr: Pointer to struct nlattr
+ *
+ * Return: 0 on success; error number otherwise
+ */
+static int hdd_get_num_tx_chains_config(struct wlan_hdd_link_info *link_info,
+					struct sk_buff *skb,
+					const struct nlattr *attr)
+{
+	uint8_t tx_chains;
+	QDF_STATUS status;
+
+	if (!hdd_is_vdev_in_conn_state(link_info)) {
+		hdd_err("Not in connected state");
+		return -EINVAL;
+	}
+
+	status = hdd_get_num_tx_chains(link_info, &tx_chains);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("Failed to get num tx chains");
+		return -EINVAL;
+	}
+
+	hdd_debug("num_tx_chains %d", tx_chains);
+	if (nla_put_u8(skb,
+		       QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS, tx_chains)) {
+		hdd_err("nla_put failure");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /**
  * hdd_get_tx_nss_config() - Get the number of tx spatial streams supported by
  * the adapter
@@ -12276,6 +12313,43 @@ static int hdd_get_tx_nss_config(struct wlan_hdd_link_info *link_info,
 	return 0;
 }
 
+/**
+ * hdd_get_num_rx_chains_config() - Get the number of rx chains supported by
+ * the adapter
+ * @link_info: Link info pointer in HDD adapter
+ * @skb: sk buffer to hold nl80211 attributes
+ * @attr: Pointer to struct nlattr
+ *
+ * Return: 0 on success; error number otherwise
+ */
+static int hdd_get_num_rx_chains_config(struct wlan_hdd_link_info *link_info,
+					struct sk_buff *skb,
+					const struct nlattr *attr)
+{
+	uint8_t rx_chains;
+	QDF_STATUS status;
+
+	if (!hdd_is_vdev_in_conn_state(link_info)) {
+		hdd_err("Not in connected state");
+		return -EINVAL;
+	}
+
+	status = hdd_get_num_rx_chains(link_info, &rx_chains);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("Failed to get num rx chains");
+		return -EINVAL;
+	}
+
+	hdd_debug("num_rx_chains %d", rx_chains);
+	if (nla_put_u8(skb,
+		       QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS, rx_chains)) {
+		hdd_err("nla_put failure");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /**
  * hdd_get_rx_nss_config() - Get the number of rx spatial streams supported by
  * the adapter
@@ -12467,6 +12541,13 @@ static const struct config_getters config_getters[] = {
 	 {QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL,
 	 sizeof(uint32_t),
 	 hdd_get_listen_interval_config},
+	 {QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS,
+	 sizeof(uint8_t),
+	 hdd_get_num_tx_chains_config},
+	 {QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS,
+	 sizeof(uint8_t),
+	 hdd_get_num_rx_chains_config},
+
 };
 
 /**