From 0a61d6462baab362e70063a950693930e114d765 Mon Sep 17 00:00:00 2001 From: Utkarsh Bhatnagar Date: Fri, 22 May 2020 20:06:49 +0530 Subject: [PATCH] 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 set antenna | all | 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 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 --- .../mlme/dispatcher/inc/wlan_mlme_api.h | 9 ++ .../mlme/dispatcher/inc/wlan_mlme_ucfg_api.h | 13 +++ .../mlme/dispatcher/src/wlan_mlme_api.c | 97 +++++++++++----- core/hdd/src/wlan_hdd_cfg80211.c | 107 +++++++++++++++++- core/hdd/src/wlan_hdd_cfg80211.h | 10 ++ core/hdd/src/wlan_hdd_main.c | 5 + 6 files changed, 211 insertions(+), 30 deletions(-) diff --git a/components/mlme/dispatcher/inc/wlan_mlme_api.h b/components/mlme/dispatcher/inc/wlan_mlme_api.h index a9fc2ea910..20079a4532 100644 --- a/components/mlme/dispatcher/inc/wlan_mlme_api.h +++ b/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 diff --git a/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h b/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h index 39dc565c00..81f7bdbd09 100644 --- a/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h +++ b/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 diff --git a/components/mlme/dispatcher/src/wlan_mlme_api.c b/components/mlme/dispatcher/src/wlan_mlme_api.c index 99fde8be82..84c64bbf03 100644 --- a/components/mlme/dispatcher/src/wlan_mlme_api.c +++ b/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; diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 9b6b622148..02bb446205 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/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, }; diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index 5688c6ba01..3a9122bb10 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/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 diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index c69df80936..4a0ecbfa13 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/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) {