Browse Source

qcacld-3.0: add vendor cmd support for BT coex chain mode

Add a new qca sub command QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.

This command is used to set BT coex chain mode via
WMI_COEX_CONFIG_BTCOEX_SEPARATE_CHAIN_MODE, it has 2 args:
arg1: BTC chain mode, including shared (0, default) and separated(1).
arg2: force restart flag. true means doing vdev restart after applying
      the new configurations; while false or NOT set means not.

CRs-Fixed: 2534768
Change-Id: I869096784e5089a6c90e94e76234cd13c9b1a13a
Yu Wang 5 years ago
parent
commit
6c9129693d

+ 7 - 0
Kbuild

@@ -273,6 +273,10 @@ ifeq ($(CONFIG_FW_THERMAL_THROTTLE), y)
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_thermal.o
 endif
 
+ifeq ($(CONFIG_QCACLD_FEATURE_BTC_CHAIN_MODE), y)
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_btc_chain_mode.o
+endif
+
 ###### OSIF_SYNC ########
 SYNC_DIR := os_if/sync
 SYNC_INC_DIR := $(SYNC_DIR)/inc
@@ -2972,6 +2976,9 @@ cppflags-$(CONFIG_QCACLD_FEATURE_MPTA_HELPER) += -DFEATURE_MPTA_HELPER
 #Flag to enable get hw capability
 cppflags-$(CONFIG_QCACLD_FEATURE_HW_CAPABILITY) += -DFEATURE_HW_CAPABILITY
 
+#Flag to enable set btc chain mode feature
+cppflags-$(CONFIG_QCACLD_FEATURE_BTC_CHAIN_MODE) += -DFEATURE_BTC_CHAIN_MODE
+
 cppflags-$(CONFIG_DATA_CE_SW_INDEX_NO_INLINE_UPDATE) += -DDATA_CE_SW_INDEX_NO_INLINE_UPDATE
 
 #Flag to enable Multi page memory allocation for RX descriptor pool

+ 192 - 0
core/hdd/src/wlan_hdd_btc_chain_mode.c

@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_hdd_btc_chain_mode.c
+ *
+ * The implementation of bt coex chain mode configuration
+ *
+ */
+
+#include "wlan_hdd_main.h"
+#include "wlan_hdd_btc_chain_mode.h"
+#include "osif_sync.h"
+#include "wlan_coex_ucfg_api.h"
+#include "wlan_hdd_object_manager.h"
+#include "wlan_cfg80211_coex.h"
+
+static QDF_STATUS
+wlan_hdd_btc_chain_mode_handler(struct wlan_objmgr_vdev *vdev)
+{
+	QDF_STATUS status;
+	struct hdd_adapter *adapter;
+	mac_handle_t mac_handle;
+	uint8_t nss, mode, band;
+	uint8_t vdev_id;
+	uint32_t freq;
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!vdev) {
+		hdd_err("NULL vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev_id = wlan_vdev_get_id(vdev);
+	if (wlan_hdd_validate_vdev_id(vdev_id)) {
+		hdd_err("Invalid vdev id: %d", vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		hdd_err("NULL psoc");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	adapter = wlan_hdd_get_adapter_from_vdev(psoc, vdev_id);
+	if (!adapter) {
+		hdd_err("NULL adapter");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = ucfg_coex_psoc_get_btc_chain_mode(psoc, &mode);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("failed to get cur BTC chain mode, status %d", status);
+		return -EFAULT;
+	}
+
+	mac_handle = adapter->hdd_ctx->mac_handle;
+	if (!mac_handle) {
+		hdd_err("NULL MAC handle");
+		return -EINVAL;
+	}
+
+	nss = ((mode == QCA_BTC_CHAIN_SEPARATED) ? 1 : 2);
+
+	hdd_debug("update nss to %d for vdev %d, device mode %d",
+		  nss, adapter->vdev_id, adapter->device_mode);
+	band = NSS_CHAINS_BAND_2GHZ;
+	sme_update_nss_in_mlme_cfg(mac_handle, nss, nss,
+				   adapter->device_mode, band);
+	sme_update_vdev_type_nss(mac_handle, nss, band);
+	hdd_store_nss_chains_cfg_in_vdev(adapter);
+	sme_update_he_cap_nss(mac_handle, adapter->vdev_id, nss);
+
+	freq = hdd_get_adapter_home_channel(adapter);
+
+	/*
+	 * BT coex chain mode is for COEX between BT and WiFi-2.4G.
+	 * Nss and related parameters have been updated upon for
+	 * NSS_CHAINS_BAND_2GHZ.
+	 * If the current home channel is NOT 2.4G, these parameters
+	 * will take effect when switching to 2.4G, so no need to do
+	 * restart here.
+	 */
+	if (!WLAN_REG_IS_24GHZ_CH_FREQ(freq))
+		return QDF_STATUS_SUCCESS;
+
+	switch (adapter->device_mode) {
+	case QDF_STA_MODE:
+	case QDF_P2P_CLIENT_MODE:
+		wlan_hdd_disconnect(adapter, 0);
+		break;
+	case QDF_SAP_MODE:
+	case QDF_P2P_GO_MODE:
+		hdd_restart_sap(adapter);
+		break;
+	default:
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void wlan_hdd_register_btc_chain_mode_handler(struct wlan_objmgr_psoc *psoc)
+{
+	ucfg_coex_register_cfg_updated_handler(psoc,
+					       COEX_CONFIG_BTC_CHAIN_MODE,
+					       wlan_hdd_btc_chain_mode_handler
+					       );
+}
+
+/**
+ * __wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to btc chain mode command parameters.
+ * @data_len: the length in byte of btc chain mode command parameters.
+ *
+ * Return: An error code or 0 on success.
+ */
+static int __wlan_hdd_cfg80211_set_btc_chain_mode(struct wiphy *wiphy,
+						  struct wireless_dev *wdev,
+						  const void *data,
+						  int data_len)
+{
+	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev);
+	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
+	int errno;
+	struct wlan_objmgr_vdev *vdev;
+
+	hdd_enter_dev(wdev->netdev);
+
+	errno = wlan_hdd_validate_context(hdd_ctx);
+	if (errno != 0)
+		return errno;
+
+	if (hdd_ctx->num_rf_chains < 2) {
+		hdd_debug("Num of chains [%u] is less than 2, setting BTC separate chain mode is not allowed",
+			  hdd_ctx->num_rf_chains);
+		return -EINVAL;
+	}
+
+	vdev = hdd_objmgr_get_vdev(adapter);
+	if (!vdev)
+		return -EINVAL;
+
+	errno = wlan_cfg80211_coex_set_btc_chain_mode(vdev, data, data_len);
+	hdd_objmgr_put_vdev(vdev);
+
+	return errno;
+}
+
+/**
+ * wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to btc chain mode command parameters.
+ * @data_len: the length in byte of btc chain mode command parameters.
+ *
+ * Return: An error code or 0 on success.
+ */
+int wlan_hdd_cfg80211_set_btc_chain_mode(struct wiphy *wiphy,
+					 struct wireless_dev *wdev,
+					 const void *data, int data_len)
+{
+	int errno;
+	struct osif_vdev_sync *vdev_sync;
+
+	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
+	if (errno)
+		return errno;
+
+	errno = __wlan_hdd_cfg80211_set_btc_chain_mode(wiphy, wdev,
+						       data, data_len);
+
+	osif_vdev_sync_op_stop(vdev_sync);
+
+	return errno;
+}

+ 67 - 0
core/hdd/src/wlan_hdd_btc_chain_mode.h

@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_hdd_btc_chain_mode.h
+ *
+ * Add Vendor subcommand QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE
+ */
+
+#ifndef __WLAN_HDD_BTC_CHAIN_MODE_H
+#define __WLAN_HDD_BTC_CHAIN_MODE_H
+
+#ifdef FEATURE_BTC_CHAIN_MODE
+#include <net/cfg80211.h>
+
+/**
+ * wlan_hdd_register_btc_chain_mode_handler() - register handler for BT coex
+ * chain mode notification.
+ * @psoc: pointer to psoc object
+ *
+ * Return: None
+ */
+void wlan_hdd_register_btc_chain_mode_handler(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to btc chain mode command parameters.
+ * @data_len: the length in byte of btc chain mode command parameters.
+ *
+ * Return: An error code or 0 on success.
+ */
+int wlan_hdd_cfg80211_set_btc_chain_mode(struct wiphy *wiphy,
+					 struct wireless_dev *wdev,
+					 const void *data, int data_len);
+
+#define FEATURE_BTC_CHAIN_MODE_COMMANDS				\
+{								\
+	.info.vendor_id = QCA_NL80211_VENDOR_ID,		\
+	.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE,\
+	.flags = WIPHY_VENDOR_CMD_NEED_WDEV |			\
+		WIPHY_VENDOR_CMD_NEED_NETDEV |			\
+		WIPHY_VENDOR_CMD_NEED_RUNNING,			\
+	.doit = wlan_hdd_cfg80211_set_btc_chain_mode			\
+},
+#else /* FEATURE_BTC_CHAIN_MODE */
+static inline void
+wlan_hdd_register_btc_chain_mode_handler(struct wlan_objmgr_psoc *psoc) {}
+
+#define FEATURE_BTC_CHAIN_MODE_COMMANDS
+#endif /* FEATURE_BTC_CHAIN_MODE */
+
+#endif /* __WLAN_HDD_BTC_CHAIN_MODE_H */

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

@@ -146,6 +146,7 @@
 #include "sme_api.h"
 #include "wlan_hdd_thermal.h"
 #include <ol_defines.h>
+#include "wlan_hdd_btc_chain_mode.h"
 
 #define g_mode_rates_size (12)
 #define a_mode_rates_size (8)
@@ -14784,6 +14785,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
 	FEATURE_MPTA_HELPER_COMMANDS
 	FEATURE_HW_CAPABILITY_COMMANDS
 	FEATURE_THERMAL_VENDOR_COMMANDS
+	FEATURE_BTC_CHAIN_MODE_COMMANDS
 };
 
 struct hdd_context *hdd_cfg80211_wiphy_alloc(void)

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

@@ -179,6 +179,7 @@
 #include "wlan_pkt_capture_ucfg_api.h"
 #include <wlan_hdd_sar_limits.h>
 #include "cfg_nan_api.h"
+#include "wlan_hdd_btc_chain_mode.h"
 
 #ifdef MODULE
 #define WLAN_MODULE_NAME  module_name(THIS_MODULE)
@@ -3464,6 +3465,8 @@ int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, bool reinit)
 		 */
 		hdd_nan_register_callbacks(hdd_ctx);
 
+		wlan_hdd_register_btc_chain_mode_handler(hdd_ctx->psoc);
+
 		status = cds_pre_enable();
 		if (!QDF_IS_STATUS_SUCCESS(status)) {
 			hdd_err("Failed to pre-enable CDS; status: %d", status);

+ 15 - 2
core/mac/src/sys/legacy/src/utils/src/parser_api.c

@@ -768,6 +768,7 @@ populate_dot11f_ht_caps(struct mac_context *mac,
 			 disable_high_ht_mcs_2x2);
 		if (pe_session->nss == NSS_1x1_MODE) {
 			pDot11f->supportedMCSSet[1] = 0;
+			pDot11f->txSTBC = 0;
 		} else if (wlan_reg_is_24ghz_ch_freq(
 			   pe_session->curr_op_freq) &&
 			   disable_high_ht_mcs_2x2 &&
@@ -1107,6 +1108,7 @@ populate_dot11f_vht_caps(struct mac_context *mac,
 				DISABLE_VHT_MCS_9(pDot11f->rxMCSMap,
 						NSS_1x1_MODE);
 			}
+			pDot11f->txSTBC = 0;
 		} else {
 			if (!pe_session->ch_width &&
 			    !vht_cap_info->enable_vht20_mcs9 &&
@@ -1119,6 +1121,7 @@ populate_dot11f_vht_caps(struct mac_context *mac,
 			}
 		}
 	}
+
 	lim_log_vht_cap(mac, pDot11f);
 	return QDF_STATUS_SUCCESS;
 }
@@ -1128,6 +1131,9 @@ populate_dot11f_vht_operation(struct mac_context *mac,
 			      struct pe_session *pe_session,
 			      tDot11fIEVHTOperation *pDot11f)
 {
+	uint32_t mcs_set;
+	struct mlme_vht_capabilities_info *vht_cap_info;
+
 	if (!pe_session || !pe_session->vhtCapability)
 		return QDF_STATUS_SUCCESS;
 
@@ -1149,9 +1155,16 @@ populate_dot11f_vht_operation(struct mac_context *mac,
 		pDot11f->chan_center_freq_seg1 = 0;
 	}
 
-	pDot11f->basicMCSSet =
-		(uint16_t)mac->mlme_cfg->vht_caps.vht_cap_info.basic_mcs_set;
+	vht_cap_info = &mac->mlme_cfg->vht_caps.vht_cap_info;
+	mcs_set = vht_cap_info->basic_mcs_set;
+	mcs_set = (mcs_set & 0xFFFC) | vht_cap_info->rx_mcs;
+
+	if (pe_session->nss == NSS_1x1_MODE)
+		mcs_set |= 0x000C;
+	else
+		mcs_set = (mcs_set & 0xFFF3) | (vht_cap_info->rx_mcs2x2 << 2);
 
+	pDot11f->basicMCSSet = (uint16_t)mcs_set;
 	lim_log_vht_operation(mac, pDot11f);
 
 	return QDF_STATUS_SUCCESS;

+ 19 - 1
core/sme/src/common/sme_api.c

@@ -59,6 +59,7 @@
 #include "wlan_mlme_main.h"
 #include "cfg_ucfg_api.h"
 #include "wlan_fwol_ucfg_api.h"
+#include <wlan_coex_ucfg_api.h>
 
 static QDF_STATUS init_sme_cmd_list(struct mac_context *mac);
 
@@ -3885,10 +3886,11 @@ sme_fill_nss_chain_params(struct mac_context *mac_ctx,
 			  enum nss_chains_band_info band,
 			  uint8_t rf_chains_supported)
 {
-	uint8_t nss_chain_shift;
+	uint8_t nss_chain_shift, btc_chain_mode;
 	uint8_t max_supported_nss;
 	struct wlan_mlme_nss_chains *nss_chains_ini_cfg =
 					&mac_ctx->mlme_cfg->nss_chains_ini_cfg;
+	QDF_STATUS status;
 
 	nss_chain_shift = sme_get_nss_chain_shift(device_mode);
 	max_supported_nss = mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable2x2 ?
@@ -3902,6 +3904,17 @@ sme_fill_nss_chain_params(struct mac_context *mac_ctx,
 	    band == NSS_CHAINS_BAND_2GHZ)
 		max_supported_nss = NSS_1x1_MODE;
 
+	status = ucfg_coex_psoc_get_btc_chain_mode(mac_ctx->psoc,
+						   &btc_chain_mode);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		sme_err("Failed to get BT coex chain mode");
+		btc_chain_mode = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED;
+	}
+
+	if (band == NSS_CHAINS_BAND_2GHZ &&
+	    btc_chain_mode == QCA_BTC_CHAIN_SEPARATED)
+		max_supported_nss = NSS_1x1_MODE;
+
 	/* If the fw doesn't support two chains, num rf chains can max be 1 */
 	vdev_ini_cfg->num_rx_chains[band] =
 		QDF_MIN(GET_VDEV_NSS_CHAIN(
@@ -3976,6 +3989,11 @@ sme_store_nss_chains_cfg_in_vdev(struct wlan_objmgr_vdev *vdev,
 	struct wlan_mlme_nss_chains *ini_cfg;
 	struct wlan_mlme_nss_chains *dynamic_cfg;
 
+	if (!vdev) {
+		sme_err("Invalid vdev");
+		return;
+	}
+
 	ini_cfg = mlme_get_ini_vdev_config(vdev);
 	dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
 

+ 18 - 0
core/wma/src/wma_dev_if.c

@@ -88,6 +88,7 @@
 #include <wlan_dfs_utils_api.h>
 #include "../../core/src/vdev_mgr_ops.h"
 #include "wlan_utility.h"
+#include "wlan_coex_ucfg_api.h"
 
 QDF_STATUS wma_find_vdev_id_by_addr(tp_wma_handle wma, uint8_t *addr,
 				    uint8_t *vdev_id)
@@ -2781,6 +2782,8 @@ QDF_STATUS wma_vdev_pre_start(uint8_t vdev_id, bool restart)
 	struct vdev_mlme_obj *mlme_obj;
 	struct wlan_objmgr_vdev *vdev = intr[vdev_id].vdev;
 	struct wlan_channel *des_chan;
+	QDF_STATUS status;
+	uint8_t btc_chain_mode;
 
 	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev);
 	if (!mlme_obj) {
@@ -2858,6 +2861,21 @@ QDF_STATUS wma_vdev_pre_start(uint8_t vdev_id, bool restart)
 	if (wma->dynamic_nss_chains_support)
 		wma_vdev_nss_chain_params_send(vdev_id, ini_cfg);
 
+	status = ucfg_coex_psoc_get_btc_chain_mode(wma->psoc, &btc_chain_mode);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		wma_err("Failed to get btc chain mode");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (btc_chain_mode != WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED) {
+		status = ucfg_coex_send_btc_chain_mode(vdev, btc_chain_mode);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			wma_err("Failed to send btc chain mode %d",
+				btc_chain_mode);
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
 	return QDF_STATUS_SUCCESS;
 }