瀏覽代碼

qcacld-3.0: Add vendor cmd to support antenna diversity

qcacld-2.0 to qcacld-3.0 propagation

Add qca_wlan_vendor_config attr to config antenna diversity.
Add vendor subcmd QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI
to get chain rssi value.

Change-Id: I75c4c8016b15772b0c52be91e446f69580475496
CRs-fixed: 1071075
lifeng 8 年之前
父節點
當前提交
d217d19d7e

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

@@ -5113,6 +5113,10 @@ wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = {
 		.type = NLA_UNSPEC,
 		.len = QDF_MAC_ADDR_SIZE},
 	[RX_BLOCKSIZE_WINLIMIT] = {.type = NLA_U32},
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL] = {.type = NLA_U32 },
 };
 
 /**
@@ -5438,6 +5442,8 @@ __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy,
 	int param_id;
 	uint32_t tx_fail_count;
 	uint32_t ant_div_usrcfg;
+	uint32_t antdiv_enable, antdiv_chain;
+	uint32_t antdiv_selftest, antdiv_selftest_intvl;
 
 	ENTER_DEV(dev);
 
@@ -5840,6 +5846,59 @@ __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy,
 	if (ret_val != 0)
 		return ret_val;
 
+	if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA]) {
+		antdiv_enable = nla_get_u32(
+			tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA]);
+		hdd_debug("antdiv_enable: %d", antdiv_enable);
+		ret_val = wma_cli_set_command((int)adapter->sessionId,
+					(int)WMI_PDEV_PARAM_ENA_ANT_DIV,
+					antdiv_enable, PDEV_CMD);
+		if (ret_val) {
+			hdd_err("Failed to set antdiv_enable");
+			return ret_val;
+		}
+	}
+
+	if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN]) {
+		antdiv_chain = nla_get_u32(
+			tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN]);
+		hdd_debug("antdiv_chain: %d", antdiv_chain);
+		ret_val = wma_cli_set_command((int)adapter->sessionId,
+					(int)WMI_PDEV_PARAM_FORCE_CHAIN_ANT,
+					antdiv_chain, PDEV_CMD);
+		if (ret_val) {
+			hdd_err("Failed to set antdiv_chain");
+			return ret_val;
+		}
+	}
+
+	if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST]) {
+		antdiv_selftest = nla_get_u32(
+			tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST]);
+		hdd_debug("antdiv_selftest: %d", antdiv_selftest);
+		ret_val = wma_cli_set_command((int)adapter->sessionId,
+					(int)WMI_PDEV_PARAM_ANT_DIV_SELFTEST,
+					antdiv_selftest, PDEV_CMD);
+		if (ret_val) {
+			hdd_err("Failed to set antdiv_selftest");
+			return ret_val;
+		}
+	}
+
+	if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL]) {
+		antdiv_selftest_intvl = nla_get_u32(
+			tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL]);
+		hdd_debug("antdiv_selftest_intvl: %d",
+			antdiv_selftest_intvl);
+		ret_val = wma_cli_set_command((int)adapter->sessionId,
+				(int)WMI_PDEV_PARAM_ANT_DIV_SELFTEST_INTVL,
+				antdiv_selftest_intvl, PDEV_CMD);
+		if (ret_val) {
+			hdd_err("Failed to set antdiv_selftest_intvl");
+			return ret_val;
+		}
+	}
+
 	return ret_val;
 }
 
@@ -10649,6 +10708,184 @@ static inline bool wlan_hdd_is_bt_in_progress(hdd_context_t *hdd_ctx)
 	return false;
 }
 
+struct chain_rssi_priv {
+	struct chain_rssi_result chain_rssi;
+};
+
+/**
+ * hdd_get_chain_rssi_cb() - Callback function to get chain rssi
+ * @context: opaque context originally passed to SME. HDD always passes
+ * a cookie for the request context
+ * @data: struct for get chain rssi
+ *
+ * This function receives the response/data from the lower layer and
+ * checks to see if the thread is still waiting then post the results to
+ * upper layer, if the request has timed out then ignore.
+ *
+ * Return: None
+ */
+static void hdd_get_chain_rssi_cb(void *context,
+				  struct chain_rssi_result *data)
+{
+	struct hdd_request *request;
+	struct chain_rssi_priv *priv;
+
+	ENTER();
+
+	request = hdd_request_get(context);
+	if (!request) {
+		hdd_err("Obsolete request");
+		return;
+	}
+
+	priv = hdd_request_priv(request);
+	priv->chain_rssi = *data;
+	hdd_request_complete(request);
+	hdd_request_put(request);
+}
+
+/**
+ * hdd_post_get_chain_rssi_rsp - send rsp to user space
+ * @hdd_ctx: pointer to hdd context
+ * @result: chain rssi result
+ *
+ * Return: 0 for success, non-zero for failure
+ */
+static int hdd_post_get_chain_rssi_rsp(hdd_context_t *hdd_ctx,
+				       struct chain_rssi_result *result)
+{
+	struct sk_buff *skb;
+	int data_len = sizeof(result->chain_rssi);
+
+	skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
+		data_len + NLA_HDRLEN + NLMSG_HDRLEN);
+
+	if (!skb) {
+		hdd_err("cfg80211_vendor_event_alloc failed");
+		return -ENOMEM;
+	}
+
+	if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_CHAIN_RSSI, data_len,
+			result->chain_rssi)) {
+		hdd_err("put fail");
+		goto nla_put_failure;
+	}
+
+	cfg80211_vendor_cmd_reply(skb);
+	return 0;
+
+nla_put_failure:
+	kfree_skb(skb);
+	return -EINVAL;
+}
+
+/**
+ * __wlan_hdd_cfg80211_get_chain_rssi() - get chain rssi
+ * @wiphy: wiphy pointer
+ * @wdev: pointer to struct wireless_dev
+ * @data: pointer to incoming NL vendor data
+ * @data_len: length of @data
+ *
+ * Return: 0 on success; error number otherwise.
+ */
+static int __wlan_hdd_cfg80211_get_chain_rssi(struct wiphy *wiphy,
+					      struct wireless_dev *wdev,
+					      const void *data,
+					      int data_len)
+{
+	hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev);
+	hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+	struct get_chain_rssi_req_params req_msg;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+	QDF_STATUS status;
+	int retval;
+	void *cookie;
+	struct hdd_request *request;
+	struct chain_rssi_priv *priv;
+	static const struct hdd_request_params params = {
+		.priv_size = sizeof(*priv),
+		.timeout_ms = WLAN_WAIT_TIME_STATS,
+	};
+
+	ENTER();
+
+	retval = wlan_hdd_validate_context(hdd_ctx);
+	if (0 != retval)
+		return retval;
+
+	if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len, NULL)) {
+		hdd_err("Invalid ATTR");
+		return -EINVAL;
+	}
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) {
+		hdd_err("attr mac addr failed");
+		return -EINVAL;
+	}
+	if (nla_len(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) !=
+		QDF_MAC_ADDR_SIZE) {
+		hdd_err("incorrect mac size");
+		return -EINVAL;
+	}
+	memcpy(&req_msg.peer_macaddr,
+		nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]),
+		QDF_MAC_ADDR_SIZE);
+	req_msg.session_id = adapter->sessionId;
+
+	request = hdd_request_alloc(&params);
+	if (!request) {
+		hdd_err("Request allocation failure");
+		return -ENOMEM;
+	}
+	cookie = hdd_request_cookie(request);
+
+	status = sme_get_chain_rssi(hdd_ctx->hHal,
+			&req_msg,
+			hdd_get_chain_rssi_cb,
+			cookie);
+	if (QDF_STATUS_SUCCESS != status) {
+		hdd_err("Unable to get chain rssi");
+		retval = qdf_status_to_os_return(status);
+	} else {
+		retval = hdd_request_wait_for_response(request);
+		if (retval) {
+			hdd_err("Target response timed out");
+		} else {
+			priv = hdd_request_priv(request);
+			retval = hdd_post_get_chain_rssi_rsp(hdd_ctx,
+					&priv->chain_rssi);
+			if (retval)
+				hdd_err("Failed to post chain rssi");
+		}
+	}
+	hdd_request_put(request);
+
+	EXIT();
+	return retval;
+}
+
+/**
+ * wlan_hdd_cfg80211_get_chain_rssi() - get chain rssi
+ * @wiphy: wiphy pointer
+ * @wdev: pointer to struct wireless_dev
+ * @data: pointer to incoming NL vendor data
+ * @data_len: length of @data
+ *
+ * Return: 0 on success; error number otherwise.
+ */
+static int wlan_hdd_cfg80211_get_chain_rssi(struct wiphy *wiphy,
+					    struct wireless_dev *wdev,
+					    const void *data,
+					    int data_len)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __wlan_hdd_cfg80211_get_chain_rssi(wiphy, wdev, data, data_len);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
 
 const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
 	{
@@ -11312,6 +11549,15 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
 	COMMON_VENDOR_COMMANDS
 #endif
 	FEATURE_11AX_VENDOR_COMMANDS
+
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			WIPHY_VENDOR_CMD_NEED_NETDEV |
+			WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = wlan_hdd_cfg80211_get_chain_rssi
+	},
 };
 
 #if ((LINUX_VERSION_CODE > KERNEL_VERSION(4, 4, 0)) || \

+ 20 - 0
core/mac/inc/sir_api.h

@@ -7452,4 +7452,24 @@ struct sir_rssi_disallow_lst {
 	int8_t expected_rssi;
 	qdf_time_t time_during_rejection;
 };
+
+/**
+ * struct chain_rssi_result - chain rssi result
+ * @chain_rssi: chain rssi result as dBm unit
+ */
+#define CHAIN_RSSI_NUM  8
+struct chain_rssi_result {
+	int32_t chain_rssi[CHAIN_RSSI_NUM];
+};
+
+/**
+ * struct get_chain_rssi_req_params - get chain rssi req params
+ * @peer_macaddr: specific peer mac address
+ * @session_id: session id
+ */
+struct get_chain_rssi_req_params {
+	struct qdf_mac_addr peer_macaddr;
+	uint8_t session_id;
+};
+
 #endif /* __SIR_API_H */

+ 17 - 0
core/sme/inc/sme_api.h

@@ -1665,4 +1665,21 @@ QDF_STATUS sme_get_peer_info_ext(tHalHandle hal,
 void sme_set_5g_band_pref(tHalHandle hal_handle,
 			  struct sme_5g_band_pref_params *pref_params);
 
+/**
+ * sme_get_chain_rssi() - Get chain rssi
+ * @hal: Global HAL handle
+ * @input: get chain rssi req params
+ * @callback: Callback function to be called with the result
+ * @context: Opaque context to be used by the caller to associate the
+ *   request with the response
+ *
+ * This function constructs the cds message and fill in message type,
+ * post the same to WDA.
+ *
+ * Return: QDF_STATUS enumeration
+ */
+QDF_STATUS sme_get_chain_rssi(tHalHandle hal,
+			      struct get_chain_rssi_req_params *input,
+			      get_chain_rssi_callback callback,
+			      void *context);
 #endif /* #if !defined( __SME_API_H ) */

+ 12 - 0
core/sme/inc/sme_internal.h

@@ -160,6 +160,16 @@ typedef void (*sme_encrypt_decrypt_callback)(
 			void *context,
 			struct sir_encrypt_decrypt_rsp_params *response);
 
+/**
+ * typedef get_chain_rssi_callback - get chain rssi callback
+ * @context: Opaque context that the client can use to associate the
+ *    callback with the request
+ * @data: chain rssi result reported by firmware
+ */
+struct chain_rssi_result;
+typedef void (*get_chain_rssi_callback)(void *context,
+					struct chain_rssi_result *data);
+
 typedef struct tagSmeStruct {
 	eSmeState state;
 	qdf_mutex_t lkSmeGlobalLock;
@@ -258,6 +268,8 @@ typedef struct tagSmeStruct {
 	void (*chip_power_save_fail_cb)(void *,
 			struct chip_pwr_save_fail_detected_params *);
 	void (*bt_activity_info_cb)(void *context, uint32_t bt_activity);
+	get_chain_rssi_callback get_chain_rssi_cb;
+	void *get_chain_rssi_context;
 } tSmeStruct, *tpSmeStruct;
 
 #endif /* #if !defined( __SMEINTERNAL_H ) */

+ 23 - 0
core/sme/src/common/sme_api.c

@@ -16507,3 +16507,26 @@ QDF_STATUS sme_set_bt_activity_info_cb(tHalHandle hal,
 
 	return status;
 }
+
+QDF_STATUS sme_get_chain_rssi(tHalHandle hal,
+			      struct get_chain_rssi_req_params *input,
+			      get_chain_rssi_callback callback,
+			      void *context)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+
+	SME_ENTER();
+
+	if (NULL == input) {
+		sme_err("Invalid req params");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mac_ctx->sme.get_chain_rssi_cb = callback;
+	mac_ctx->sme.get_chain_rssi_context = context;
+	wma_get_chain_rssi(hal, input);
+
+	SME_EXIT();
+	return status;
+}

+ 11 - 0
core/wma/inc/wma.h

@@ -2586,4 +2586,15 @@ QDF_STATUS wma_configure_smps_params(uint32_t vdev_id, uint32_t param_id,
 int wma_chip_power_save_failure_detected_handler(void *handle,
 						 uint8_t *cmd_param_info,
 						 uint32_t len);
+
+/**
+ * wma_get_chain_rssi() - send wmi cmd to get chain rssi
+ * @wma_handle: wma handler
+ * @req_params: requset params
+ *
+ * Return: Return QDF_STATUS
+ */
+QDF_STATUS wma_get_chain_rssi(tp_wma_handle wma_handle,
+		struct get_chain_rssi_req_params *req_params);
+
 #endif

+ 15 - 0
core/wma/inc/wma_internal.h

@@ -1327,4 +1327,19 @@ int wma_rx_aggr_failure_event_handler(void *handle, u_int8_t *event_buf,
  */
 int wma_wlan_bt_activity_evt_handler(void *handle, uint8_t *event,
 				     uint32_t len);
+
+/**
+ * wma_peer_ant_info_evt_handler - event handler to handle antenna info
+ * @handle: the wma handle
+ * @event: buffer with event
+ * @len: buffer length
+ *
+ * This function receives antenna info from firmware and passes the event
+ * to upper layer
+ *
+ * Return: 0 on success
+ */
+int wma_peer_ant_info_evt_handler(void *handle, u_int8_t *event,
+	u_int32_t len);
+
 #endif

+ 55 - 0
core/wma/src/wma_features.c

@@ -5373,3 +5373,58 @@ int wma_wlan_bt_activity_evt_handler(void *handle, uint8_t *event, uint32_t len)
 
 	return 0;
 }
+
+int wma_peer_ant_info_evt_handler(void *handle, u_int8_t *event,
+	u_int32_t len)
+{
+	wmi_peer_antdiv_info *peer_ant_info;
+	WMI_PEER_ANTDIV_INFO_EVENTID_param_tlvs *param_buf;
+	wmi_peer_antdiv_info_event_fixed_param *fix_param;
+	struct chain_rssi_result *chain_rssi_result;
+	u_int32_t chain_index;
+
+	tpAniSirGlobal pmac = (tpAniSirGlobal)cds_get_context(
+					QDF_MODULE_ID_PE);
+	if (!pmac) {
+		WMA_LOGE("%s: Invalid pmac", __func__);
+		return -EINVAL;
+	}
+
+	param_buf = (WMI_PEER_ANTDIV_INFO_EVENTID_param_tlvs *) event;
+	if (!param_buf) {
+		WMA_LOGE("Invalid peer_ant_info event buffer");
+		return -EINVAL;
+	}
+	fix_param = param_buf->fixed_param;
+	peer_ant_info = param_buf->peer_info;
+
+	WMA_LOGD("num_peers=%d\tvdev_id=%d",
+		fix_param->num_peers, fix_param->vdev_id);
+	WMA_LOGD("peer_ant_info: %p", peer_ant_info);
+
+	if (!peer_ant_info) {
+		WMA_LOGE("Invalid peer_ant_info ptr");
+		return -EINVAL;
+	}
+
+	chain_rssi_result = qdf_mem_malloc(sizeof(*chain_rssi_result));
+	if (!chain_rssi_result) {
+		WMA_LOGE("%s: Failed to malloc", __func__);
+		return -ENOMEM;
+	}
+
+	for (chain_index = 0; chain_index < CHAIN_RSSI_NUM; chain_index++)
+		WMA_LOGD("chain%d rssi: %x", chain_index,
+				peer_ant_info->chain_rssi[chain_index]);
+
+	qdf_mem_copy(chain_rssi_result->chain_rssi,
+				peer_ant_info->chain_rssi,
+				sizeof(peer_ant_info->chain_rssi));
+
+	pmac->sme.get_chain_rssi_cb(pmac->sme.get_chain_rssi_context,
+				chain_rssi_result);
+
+	qdf_mem_free(chain_rssi_result);
+
+	return 0;
+}

+ 45 - 0
core/wma/src/wma_main.c

@@ -2707,6 +2707,11 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, void *cds_context,
 	}
 
 	wma_ndp_register_all_event_handlers(wma_handle);
+	wmi_unified_register_event_handler(wma_handle->wmi_handle,
+				WMI_PEER_ANTDIV_INFO_EVENTID,
+				wma_peer_ant_info_evt_handler,
+				WMA_RX_WORK_CTX);
+
 
 	wma_register_debug_callback();
 	/* Register callback with PMO so PMO can update the vdev pause bitmap*/
@@ -6674,6 +6679,46 @@ QDF_STATUS wma_set_rx_blocksize(tp_wma_handle wma_handle,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS wma_get_chain_rssi(tp_wma_handle wma_handle,
+		struct get_chain_rssi_req_params *req_params)
+{
+	wmi_peer_antdiv_info_req_cmd_fixed_param *cmd;
+	wmi_buf_t wmi_buf;
+	uint32_t len = sizeof(wmi_peer_antdiv_info_req_cmd_fixed_param);
+	u_int8_t *buf_ptr;
+
+	if (!wma_handle) {
+		WMA_LOGE(FL("WMA is closed, can not issue cmd"));
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
+	if (!wmi_buf) {
+		WMA_LOGE(FL("wmi_buf_alloc failed"));
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	buf_ptr = (u_int8_t *)wmi_buf_data(wmi_buf);
+
+	cmd = (wmi_peer_antdiv_info_req_cmd_fixed_param *)buf_ptr;
+	WMITLV_SET_HDR(&cmd->tlv_header,
+		WMITLV_TAG_STRUC_wmi_peer_antdiv_info_req_cmd_fixed_param,
+		WMITLV_GET_STRUCT_TLVLEN(
+		wmi_peer_antdiv_info_req_cmd_fixed_param));
+	cmd->vdev_id = req_params->session_id;
+	WMI_CHAR_ARRAY_TO_MAC_ADDR(req_params->peer_macaddr.bytes,
+				&cmd->peer_mac_address);
+
+	if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
+				 WMI_PEER_ANTDIV_INFO_REQ_CMDID)) {
+		WMA_LOGE(FL("failed to send get chain rssi command"));
+		wmi_buf_free(wmi_buf);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /**
  * wma_mc_process_msg() - process wma messages and call appropriate function.
  * @cds_context: cds context