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) {