Browse Source

qcacld-3.0: Implemented Chainmask NL command

Implemented driver interface for NL command for setting
and getting TX and RX chains. The chains can be set to
either chain 0(1) or chain 1(2) or both(3). This is only valid if
antenna mode is set to 2X2.

Below command can be used to set the chainmask:
iw phy <phyname> set antenna <bitmap> | all | <tx bitmap> <rx bitmap>
Example:
iw phy0 set antenna 1   -- to set both Tx and Rx chain 0.
iw phy0 set antenna all -- to set all/both chains for rx/tx
iw phy0 set antenna 1 2 -- to set chain 0 for tx and chain 1 for rx

Below command can be used to get the chainmask after set:
iw phy <phyname> info

check for "Configured Antennas: TX 0x1 RX 0x1"

Below conditions should be met for setting chainmask:
1. Antenna sharing should be disabled.
2. gEnable2x2 in ini file should be 0
3. enableBTChainSeparation in ini file should be 1
4. DBS should be disabled (gDualMacFeatureDisable = 1)
   or HW should be DBS 2x2 capable
5. set TX/RX chainmask 3 in ini (gSetTxChainmask1x1/gSetRxChainmask1x1)
6. HW should support TX/RX chainmask as 3

Change-Id: I04f6667398eac405a6be61bc039e048090578abf
CRs-Fixed: 2693370
Utkarsh Bhatnagar 4 years ago
parent
commit
0a61d6462b

+ 9 - 0
components/mlme/dispatcher/inc/wlan_mlme_api.h

@@ -494,6 +494,15 @@ QDF_STATUS wlan_mlme_get_bt_chain_separation_flag(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS wlan_mlme_configure_chain_mask(struct wlan_objmgr_psoc *psoc,
 					  uint8_t session_id);
 
+/**
+ * wlan_mlme_is_chain_mask_supported() - check if configure chainmask can
+ * be supported
+ * @psoc: pointer to psoc object
+ *
+ * Return: true if supported else false
+ */
+bool wlan_mlme_is_chain_mask_supported(struct wlan_objmgr_psoc *psoc);
+
 /**
  * wlan_mlme_get_listen_interval() - Get listen interval
  * @psoc: pointer to psoc object

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

@@ -675,6 +675,19 @@ QDF_STATUS ucfg_mlme_configure_chain_mask(struct wlan_objmgr_psoc *psoc,
 	return wlan_mlme_configure_chain_mask(psoc, session_id);
 }
 
+/**
+ * ucfg_mlme_is_chain_mask_supported() - check if configure chainmask can
+ * be supported
+ * @psoc: pointer to psoc object
+ *
+ * Return: true if supported else false
+ */
+static inline
+bool ucfg_mlme_is_chain_mask_supported(struct wlan_objmgr_psoc *psoc)
+{
+	return wlan_mlme_is_chain_mask_supported(psoc);
+}
+
 /*
  * ucfg_mlme_get_sta_keep_alive_period() - Get the sta keep alive period
  * @psoc: pointer to psoc object

+ 68 - 29
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -881,28 +881,26 @@ QDF_STATUS wlan_mlme_get_num_11ag_tx_chains(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS wlan_mlme_configure_chain_mask(struct wlan_objmgr_psoc *psoc,
-					  uint8_t session_id)
+
+static
+bool wlan_mlme_configure_chain_mask_supported(struct wlan_objmgr_psoc *psoc)
 {
-	int ret_val;
-	uint8_t ch_msk_val;
 	struct wma_caps_per_phy non_dbs_phy_cap = {0};
 	struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc);
 	QDF_STATUS status;
-	bool enable2x2, as_enabled, enable_bt_chain_sep;
+	bool as_enabled, enable_bt_chain_sep, enable2x2;
 	uint8_t dual_mac_feature;
-	bool hw_dbs_2x2_cap, mrc_disabled_2g_rx, mrc_disabled_2g_tx;
-	bool mrc_disabled_5g_rx, mrc_disabled_5g_tx;
+	bool hw_dbs_2x2_cap;
 
 	if (!mlme_obj)
-		return QDF_STATUS_E_FAILURE;
+		return false;
 
 	status = wma_get_caps_for_phyidx_hwmode(&non_dbs_phy_cap,
 						HW_MODE_DBS_NONE,
 						CDS_BAND_ALL);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		mlme_legacy_err("couldn't get phy caps. skip chain mask programming");
-		return status;
+		return false;
 	}
 
 	if (non_dbs_phy_cap.tx_chain_mask_2G < 3 ||
@@ -910,32 +908,62 @@ QDF_STATUS wlan_mlme_configure_chain_mask(struct wlan_objmgr_psoc *psoc,
 	    non_dbs_phy_cap.tx_chain_mask_5G < 3 ||
 	    non_dbs_phy_cap.rx_chain_mask_5G < 3) {
 		mlme_legacy_debug("firmware not capable. skip chain mask programming");
-		return 0;
+		return false;
 	}
 
-	enable2x2 = mlme_obj->cfg.vht_caps.vht_cap_info.enable2x2;
 	enable_bt_chain_sep =
 			mlme_obj->cfg.chainmask_cfg.enable_bt_chain_separation;
 	as_enabled = mlme_obj->cfg.gen.as_enabled;
 	ucfg_policy_mgr_get_dual_mac_feature(psoc, &dual_mac_feature);
 
 	hw_dbs_2x2_cap = policy_mgr_is_hw_dbs_2x2_capable(psoc);
-	mrc_disabled_2g_rx =
-	  mlme_obj->cfg.nss_chains_ini_cfg.disable_rx_mrc[NSS_CHAINS_BAND_2GHZ];
-	mrc_disabled_2g_tx =
-	  mlme_obj->cfg.nss_chains_ini_cfg.disable_tx_mrc[NSS_CHAINS_BAND_2GHZ];
-	mrc_disabled_5g_rx =
-	  mlme_obj->cfg.nss_chains_ini_cfg.disable_rx_mrc[NSS_CHAINS_BAND_5GHZ];
-	mrc_disabled_5g_tx =
-	  mlme_obj->cfg.nss_chains_ini_cfg.disable_tx_mrc[NSS_CHAINS_BAND_5GHZ];
+	enable2x2 = mlme_obj->cfg.vht_caps.vht_cap_info.enable2x2;
 
-	mlme_legacy_debug("enable2x2 %d enable_bt_chain_sep %d dual mac feature %d antenna sharing %d HW 2x2 cap %d",
-			  enable2x2, enable_bt_chain_sep, dual_mac_feature,
-			  as_enabled, hw_dbs_2x2_cap);
+	if (!enable_bt_chain_sep || as_enabled || enable2x2 ||
+	   (!hw_dbs_2x2_cap && dual_mac_feature != DISABLE_DBS_CXN_AND_SCAN)) {
+		mlme_legacy_debug("Cannot configure chainmask enable_bt_chain_sep %d as_enabled %d enable2x2 %d hw_dbs_2x2_cap %d dual_mac_feature %d",
+				  enable_bt_chain_sep, as_enabled, enable2x2,
+				  hw_dbs_2x2_cap, dual_mac_feature);
+		return false;
+	}
 
-	mlme_legacy_debug("MRC values TX:- 2g %d 5g %d RX:- 2g %d 5g %d",
-			  mrc_disabled_2g_tx, mrc_disabled_5g_tx,
-			  mrc_disabled_2g_rx, mrc_disabled_5g_rx);
+	return true;
+}
+
+bool wlan_mlme_is_chain_mask_supported(struct wlan_objmgr_psoc *psoc)
+
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc);
+
+	if (!mlme_obj)
+		return false;
+
+	if (!wlan_mlme_configure_chain_mask_supported(psoc))
+		return false;
+
+	/* If user has configured 1x1 from INI */
+	if (mlme_obj->cfg.chainmask_cfg.txchainmask1x1 != 3 ||
+	    mlme_obj->cfg.chainmask_cfg.rxchainmask1x1 != 3) {
+		mlme_legacy_debug("txchainmask1x1 %d rxchainmask1x1 %d",
+				  mlme_obj->cfg.chainmask_cfg.txchainmask1x1,
+				  mlme_obj->cfg.chainmask_cfg.rxchainmask1x1);
+		return false;
+	}
+
+	return true;
+
+}
+QDF_STATUS wlan_mlme_configure_chain_mask(struct wlan_objmgr_psoc *psoc,
+					  uint8_t session_id)
+{
+	int ret_val;
+	uint8_t ch_msk_val;
+	struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	bool mrc_disabled_2g_rx, mrc_disabled_2g_tx;
+	bool mrc_disabled_5g_rx, mrc_disabled_5g_tx;
+
+	if (!mlme_obj)
+		return QDF_STATUS_E_FAILURE;
 
 	mlme_legacy_debug("txchainmask1x1: %d rxchainmask1x1: %d",
 			  mlme_obj->cfg.chainmask_cfg.txchainmask1x1,
@@ -947,11 +975,22 @@ QDF_STATUS wlan_mlme_configure_chain_mask(struct wlan_objmgr_psoc *psoc,
 			  mlme_obj->cfg.chainmask_cfg.tx_chain_mask_5g,
 			  mlme_obj->cfg.chainmask_cfg.rx_chain_mask_5g);
 
-	if (enable2x2 || !enable_bt_chain_sep || as_enabled ||
-	   (!hw_dbs_2x2_cap && dual_mac_feature != DISABLE_DBS_CXN_AND_SCAN)) {
-		mlme_legacy_debug("Cannot configure chainmask to FW");
+	mrc_disabled_2g_rx =
+	  mlme_obj->cfg.nss_chains_ini_cfg.disable_rx_mrc[NSS_CHAINS_BAND_2GHZ];
+	mrc_disabled_2g_tx =
+	  mlme_obj->cfg.nss_chains_ini_cfg.disable_tx_mrc[NSS_CHAINS_BAND_2GHZ];
+	mrc_disabled_5g_rx =
+	  mlme_obj->cfg.nss_chains_ini_cfg.disable_rx_mrc[NSS_CHAINS_BAND_5GHZ];
+	mrc_disabled_5g_tx =
+	  mlme_obj->cfg.nss_chains_ini_cfg.disable_tx_mrc[NSS_CHAINS_BAND_5GHZ];
+
+	mlme_legacy_debug("MRC values TX:- 2g %d 5g %d RX:- 2g %d 5g %d",
+			  mrc_disabled_2g_tx, mrc_disabled_5g_tx,
+			  mrc_disabled_2g_rx, mrc_disabled_5g_rx);
+
+	if (!wlan_mlme_configure_chain_mask_supported(psoc))
 		return QDF_STATUS_E_FAILURE;
-	}
+
 
 	if (mlme_obj->cfg.chainmask_cfg.txchainmask1x1) {
 		ch_msk_val = mlme_obj->cfg.chainmask_cfg.txchainmask1x1;

+ 106 - 1
core/hdd/src/wlan_hdd_cfg80211.c

@@ -22618,6 +22618,110 @@ void hdd_send_update_owe_info_event(struct hdd_adapter *adapter,
 }
 #endif
 
+static int __wlan_hdd_cfg80211_set_chainmask(struct wiphy *wiphy,
+					     uint32_t tx_mask,
+					     uint32_t rx_mask)
+{
+	int ret;
+	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
+	enum hdd_chain_mode chains;
+
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret) {
+		hdd_err_rl("Invalid Hdd Context");
+		return -EINVAL;
+	}
+	if (hdd_ctx->num_rf_chains != HDD_ANTENNA_MODE_2X2 ||
+	    !ucfg_mlme_is_chain_mask_supported(hdd_ctx->psoc)) {
+		hdd_info_rl("Chainmask can't be configured, num of rf chain %d",
+			    hdd_ctx->num_rf_chains);
+		return -ENOTSUPP;
+	}
+	chains = HDD_CHAIN_MODE_2X2;
+	if (!tx_mask || tx_mask > chains || !rx_mask || rx_mask > chains) {
+		hdd_err_rl("Invalid masks. txMask: %d rxMask: %d num_rf_chains: %d",
+			   tx_mask, rx_mask, hdd_ctx->num_rf_chains);
+
+		return -EINVAL;
+	}
+
+	ret = wma_cli_set_command(0, WMI_PDEV_PARAM_TX_CHAIN_MASK,
+				  tx_mask, PDEV_CMD);
+	if (ret)
+		hdd_err_rl("Failed to set TX the mask");
+
+	ret = wma_cli_set_command(0, WMI_PDEV_PARAM_RX_CHAIN_MASK,
+				  rx_mask, PDEV_CMD);
+	if (ret)
+		hdd_err_rl("Failed to set RX the mask");
+
+	return ret;
+}
+
+static int wlan_hdd_cfg80211_set_chainmask(struct wiphy *wiphy,
+					   uint32_t tx_mask,
+					   uint32_t rx_mask)
+{
+	struct osif_psoc_sync *psoc_sync;
+	int errno;
+
+	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
+	if (errno)
+		return errno;
+
+	errno = __wlan_hdd_cfg80211_set_chainmask(wiphy, tx_mask, rx_mask);
+	osif_psoc_sync_op_stop(psoc_sync);
+
+	return errno;
+}
+
+static int __wlan_hdd_cfg80211_get_chainmask(struct wiphy *wiphy,
+					     uint32_t *tx_mask,
+					     uint32_t *rx_mask)
+
+{
+	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
+	int ret;
+
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret) {
+		hdd_err_rl("Invalid Hdd Context");
+		return -EINVAL;
+	}
+	*tx_mask = wma_cli_get_command(0, WMI_PDEV_PARAM_TX_CHAIN_MASK,
+				       PDEV_CMD);
+	*rx_mask = wma_cli_get_command(0, WMI_PDEV_PARAM_RX_CHAIN_MASK,
+				       PDEV_CMD);
+
+	/* if 0 return max value as 0 mean no set cmnd received yet */
+	if (!*tx_mask)
+		*tx_mask = hdd_ctx->num_rf_chains == HDD_ANTENNA_MODE_2X2 ?
+				HDD_CHAIN_MODE_2X2 : HDD_CHAIN_MODE_1X1;
+	if (!*rx_mask)
+		*rx_mask = hdd_ctx->num_rf_chains == HDD_ANTENNA_MODE_2X2 ?
+				HDD_CHAIN_MODE_2X2 : HDD_CHAIN_MODE_1X1;
+	hdd_debug("tx_mask: %d rx_mask: %d", *tx_mask, *rx_mask);
+
+	return 0;
+}
+
+static int wlan_hdd_cfg80211_get_chainmask(struct wiphy *wiphy,
+					   uint32_t *tx_mask,
+					   uint32_t *rx_mask)
+{
+	struct osif_psoc_sync *psoc_sync;
+	int errno;
+
+	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
+	if (errno)
+		return errno;
+
+	errno = __wlan_hdd_cfg80211_get_chainmask(wiphy, tx_mask, rx_mask);
+	osif_psoc_sync_op_stop(psoc_sync);
+
+	return errno;
+}
+
 /**
  * struct cfg80211_ops - cfg80211_ops
  *
@@ -22760,5 +22864,6 @@ static struct cfg80211_ops wlan_hdd_cfg80211_ops = {
 	.del_nan_func = wlan_hdd_cfg80211_del_nan_func,
 	.nan_change_conf = wlan_hdd_cfg80211_nan_change_conf,
 #endif
-
+	.set_antenna = wlan_hdd_cfg80211_set_chainmask,
+	.get_antenna = wlan_hdd_cfg80211_get_chainmask,
 };

+ 10 - 0
core/hdd/src/wlan_hdd_cfg80211.h

@@ -640,6 +640,16 @@ enum hdd_rate_info_bw {
 	HDD_RATE_BW_160,
 };
 
+/**
+ * hdd_chain_mode : Representation of Number of chains available.
+ * @HDD_CHAIN_MODE_1X1: Chain mask Not Configurable as only one chain available
+ * @HDD_CHAIN_MODE_2X2: Chain mask configurable as both chains available
+ */
+enum hdd_chain_mode {
+	HDD_CHAIN_MODE_1X1 = 1,
+	HDD_CHAIN_MODE_2X2 = 3,
+};
+
 /**
  * hdd_set_rate_bw(): Set the bandwidth for the given rate_info
  * @info: The rate info for which the bandwidth should be set

+ 5 - 0
core/hdd/src/wlan_hdd_main.c

@@ -8584,6 +8584,11 @@ static int hdd_wiphy_init(struct hdd_context *hdd_ctx)
 		wiphy->features |= NL80211_FEATURE_NEED_OBSS_SCAN;
 	}
 
+	if (hdd_ctx->num_rf_chains == HDD_ANTENNA_MODE_2X2 &&
+	    ucfg_mlme_is_chain_mask_supported(hdd_ctx->psoc)) {
+		wiphy->available_antennas_tx = HDD_CHAIN_MODE_2X2;
+		wiphy->available_antennas_rx = HDD_CHAIN_MODE_2X2;
+	}
 	/* registration of wiphy dev with cfg80211 */
 	ret_val = wlan_hdd_cfg80211_register(wiphy);
 	if (0 > ret_val) {