Переглянути джерело

qcacld-3.0: Add support to query RCPI info

RCPI is measure of received RF power in the selected channel for a
received frame and is measured at the antenna connector and shall be
measured over an entire frame. It is a monotonically increasing,
logarithmic function of received power level.

Wlan firmware computes RCPI.

Add host support to query firmware for RCPI information of peer
mac address in sta, p2p client, softap and p2p go modes.

Change-Id: I43a061ad4ed0fceb66dbd82b1c35b7678ee2259c
CRs-Fixed: 1092612
Rajeev Kumar Sirasanagandla 8 роки тому
батько
коміт
996e529f9d

+ 17 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -204,6 +204,9 @@
 /* Maximum time(ms) to wait for RSO CMD status event */
 #define WAIT_TIME_RSO_CMD_STATUS 2000
 
+/* rcpi request timeout in milli seconds */
+#define WLAN_WAIT_TIME_RCPI 500
+
 #define MAX_NUMBER_OF_ADAPTERS 4
 
 #define MAX_CFG_STRING_LEN  255
@@ -961,6 +964,16 @@ struct hdd_connect_pm_context {
 #endif
 #endif
 
+/**
+ * struct rcpi_info - rcpi info
+ * @rcpi: computed value in dB
+ * @mac_addr: peer mac addr for which rcpi is computed
+ */
+struct rcpi_info {
+	int32_t rcpi;
+	struct qdf_mac_addr mac_addr;
+};
+
 struct hdd_context;
 
 struct hdd_adapter {
@@ -1204,6 +1217,9 @@ struct hdd_adapter {
 	uint8_t active_ac;
 	uint32_t mon_chan;
 	uint32_t mon_bandwidth;
+
+	/* rcpi information */
+	struct rcpi_info rcpi;
 };
 
 #define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->sessionCtx.station)
@@ -1681,6 +1697,7 @@ struct hdd_context {
 	uint8_t scan_reject_cnt;
 	bool dfs_cac_offload;
 	bool reg_offload;
+	bool rcpi_enabled;
 #ifdef FEATURE_WLAN_CH_AVOID
 	struct ch_avoid_ind_type coex_avoid_freq_list;
 	struct ch_avoid_ind_type dnbs_avoid_freq_list;

+ 28 - 0
core/hdd/src/wlan_hdd_hostapd.c

@@ -6264,6 +6264,9 @@ QDF_STATUS hdd_init_ap_mode(struct hdd_adapter *adapter, bool reinit)
 			     sizeof(struct sap_acs_cfg));
 	}
 
+	/* rcpi info initialization */
+	qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi));
+
 	EXIT();
 
 	return status;
@@ -8949,3 +8952,28 @@ void hdd_sap_destroy_events(struct hdd_adapter *adapter)
 	EXIT();
 }
 
+bool hdd_is_peer_associated(struct hdd_adapter *adapter,
+			    struct qdf_mac_addr *mac_addr)
+{
+	uint32_t cnt;
+	struct hdd_station_info *sta_info;
+
+	if (!adapter || !mac_addr) {
+		hdd_err("Invalid adapter or mac_addr");
+		return false;
+	}
+
+	sta_info = adapter->sta_info;
+	spin_lock_bh(&adapter->sta_info_lock);
+	for (cnt = 0; cnt < WLAN_MAX_STA_COUNT; cnt++) {
+		if ((sta_info[cnt].in_use) &&
+		    !qdf_mem_cmp(&(sta_info[cnt].sta_mac), mac_addr,
+		    QDF_MAC_ADDR_SIZE))
+			break;
+	}
+	spin_unlock_bh(&adapter->sta_info_lock);
+	if (cnt != WLAN_MAX_STA_COUNT)
+		return true;
+
+	return false;
+}

+ 13 - 0
core/hdd/src/wlan_hdd_hostapd.h

@@ -147,6 +147,19 @@ int wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy,
 				    struct net_device *dev,
 				    struct cfg80211_beacon_data *params);
 
+/**
+ * hdd_is_peer_associated - is peer connected to softap
+ * @adapter: pointer to softap adapter
+ * @mac_addr: address to check in peer list
+ *
+ * This function has to be invoked only when bss is started and is used
+ * to check whether station with specified addr is peer or not
+ *
+ * Return: true if peer mac, else false
+ */
+bool hdd_is_peer_associated(struct hdd_adapter *adapter,
+			    struct qdf_mac_addr *mac_addr);
+
 int hdd_destroy_acs_timer(struct hdd_adapter *adapter);
 
 QDF_STATUS wlan_hdd_config_acs(struct hdd_context *hdd_ctx,

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

@@ -1793,6 +1793,7 @@ void hdd_update_tgt_cfg(void *context, void *param)
 
 	hdd_ctx->bpf_enabled = (cfg->bpf_enabled &&
 				hdd_ctx->config->bpf_packet_filter_enable);
+	hdd_ctx->rcpi_enabled = cfg->rcpi_enabled;
 	hdd_update_ra_rate_limit(hdd_ctx, cfg);
 
 	if ((hdd_ctx->config->txBFCsnValue >
@@ -3503,6 +3504,10 @@ QDF_STATUS hdd_init_station_mode(struct hdd_adapter *adapter)
 		hdd_err("WMI_PDEV_PARAM_BURST_ENABLE set failed %d", ret_val);
 
 	adapter->dev->features |= NETIF_F_LRO;
+
+	/* rcpi info initialization */
+	qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi));
+
 	return QDF_STATUS_SUCCESS;
 
 error_wmm_init:

+ 235 - 0
core/hdd/src/wlan_hdd_stats.c

@@ -34,6 +34,8 @@
 #include "hif.h"
 #include <qca_vendor.h>
 #include "wma_api.h"
+#include "wlan_hdd_hostapd.h"
+#include "wlan_hdd_request_manager.h"
 #include "wlan_hdd_debugfs_llstat.h"
 
 /* 11B, 11G Rate table include Basic rate and Extended rate
@@ -4706,3 +4708,236 @@ void hdd_clear_hif_stats(void)
 		return;
 	hif_clear_stats(hif_ctx);
 }
+
+/**
+ * hdd_is_rcpi_applicable() - validates RCPI request
+ * @adapter: adapter upon which the measurement is requested
+ * @mac_addr: peer addr for which measurement is requested
+ * @rcpi_value: pointer to where the RCPI should be returned
+ * @reassoc: used to return cached RCPI during reassoc
+ *
+ * Return: true for success, false for failure
+ */
+
+static bool hdd_is_rcpi_applicable(struct hdd_adapter *adapter,
+				   struct qdf_mac_addr *mac_addr,
+				   int32_t *rcpi_value,
+				   bool *reassoc)
+{
+	struct hdd_station_ctx *hdd_sta_ctx;
+
+	if (adapter->device_mode == QDF_STA_MODE ||
+	    adapter->device_mode == QDF_P2P_CLIENT_MODE) {
+		hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+		if (hdd_sta_ctx->conn_info.connState !=
+		    eConnectionState_Associated)
+			return false;
+
+		if (hdd_sta_ctx->hdd_reassoc_scenario) {
+			/* return the cached rcpi, if mac addr matches */
+			hdd_debug("Roaming in progress, return cached RCPI");
+			if (!qdf_mem_cmp(&adapter->rcpi.mac_addr,
+					 mac_addr, sizeof(*mac_addr))) {
+				*rcpi_value = adapter->rcpi.rcpi;
+				*reassoc = true;
+				return true;
+			}
+			return false;
+		}
+
+		if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssId,
+				sizeof(*mac_addr))) {
+			hdd_err("mac addr is different from bssid connected");
+			return false;
+		}
+	} else if (adapter->device_mode == QDF_SAP_MODE ||
+		   adapter->device_mode == QDF_P2P_GO_MODE) {
+		if (!test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) {
+			hdd_err("Invalid rcpi request, softap not started");
+			return false;
+		}
+
+		/* check if peer mac addr is associated to softap */
+		if (!hdd_is_peer_associated(adapter, mac_addr)) {
+			hdd_err("invalid peer mac-addr: not associated");
+			return false;
+		}
+	} else {
+		hdd_err("Invalid rcpi request");
+		return false;
+	}
+
+	*reassoc = false;
+	return true;
+}
+
+/**
+ * wlan_hdd_get_rcpi_cb() - callback function for rcpi response
+ * @context: Pointer to rcpi context
+ * @rcpi_req: Pointer to rcpi response
+ *
+ * Return: None
+ */
+static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr,
+				 int32_t rcpi, QDF_STATUS status)
+{
+	struct hdd_request *request;
+	struct rcpi_info *priv;
+
+	if (!context) {
+		hdd_err("No rcpi context");
+		return;
+	}
+
+	request = hdd_request_get(context);
+	if (!request) {
+		hdd_err("Obsolete RCPI request");
+		return;
+	}
+
+	priv = hdd_request_priv(request);
+	priv->mac_addr = mac_addr;
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		priv->rcpi = 0;
+		hdd_err("Error in computing RCPI");
+	} else {
+		priv->rcpi = rcpi;
+	}
+
+	hdd_request_complete(request);
+	hdd_request_put(request);
+}
+
+/**
+ * __wlan_hdd_get_rcpi() - local function to get RCPI
+ * @adapter: adapter upon which the measurement is requested
+ * @mac: peer addr for which measurement is requested
+ * @rcpi_value: pointer to where the RCPI should be returned
+ * @measurement_type: type of rcpi measurement
+ *
+ * Return: 0 for success, non-zero for failure
+ */
+static int __wlan_hdd_get_rcpi(struct hdd_adapter *adapter,
+			       uint8_t *mac,
+			       int32_t *rcpi_value,
+			       enum rcpi_measurement_type measurement_type)
+{
+	struct hdd_context *hdd_ctx;
+	int status = 0, ret = 0;
+	struct qdf_mac_addr mac_addr;
+	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	struct sme_rcpi_req *rcpi_req;
+	void *cookie;
+	struct rcpi_info *priv;
+	struct hdd_request *request;
+	static const struct hdd_request_params params = {
+		.priv_size = sizeof(*priv),
+		.timeout_ms = WLAN_WAIT_TIME_RCPI,
+	};
+	bool reassoc;
+
+	ENTER();
+
+	/* initialize the rcpi value to zero, useful in error cases */
+	*rcpi_value = 0;
+
+	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
+		hdd_err("Command not allowed in FTM mode");
+		return -EINVAL;
+	}
+
+	if (!adapter) {
+		hdd_warn("adapter context is NULL");
+		return -EINVAL;
+	}
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	status = wlan_hdd_validate_context(hdd_ctx);
+	if (status)
+		return -EINVAL;
+
+	if (!hdd_ctx->rcpi_enabled) {
+		hdd_debug("RCPI not supported");
+		return -EINVAL;
+	}
+
+	if (!mac) {
+		hdd_warn("RCPI peer mac-addr is NULL");
+		return -EINVAL;
+	}
+
+	qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE);
+
+	if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc))
+		return -EINVAL;
+	if (reassoc)
+		return 0;
+
+	rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req));
+	if (!rcpi_req) {
+		hdd_err("unable to allocate memory for RCPI req");
+		return -EINVAL;
+	}
+
+	request = hdd_request_alloc(&params);
+	if (!request) {
+		hdd_err("Request allocation failure");
+		qdf_mem_free(rcpi_req);
+		return -ENOMEM;
+	}
+	cookie = hdd_request_cookie(request);
+
+	rcpi_req->mac_addr = mac_addr;
+	rcpi_req->session_id = adapter->sessionId;
+	rcpi_req->measurement_type = measurement_type;
+	rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb;
+	rcpi_req->rcpi_context = cookie;
+
+	qdf_status = sme_get_rcpi(hdd_ctx->hHal, rcpi_req);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		hdd_err("Unable to retrieve RCPI");
+		status = qdf_status_to_os_return(qdf_status);
+		goto out;
+	}
+
+	/* request was sent -- wait for the response */
+	ret = hdd_request_wait_for_response(request);
+	if (ret) {
+		hdd_err("SME timed out while retrieving RCPI");
+		status = -EINVAL;
+		goto out;
+	}
+
+	/* update the adapter with the fresh results */
+	priv = hdd_request_priv(request);
+	adapter->rcpi.mac_addr = priv->mac_addr;
+	adapter->rcpi.rcpi = priv->rcpi;
+	if (qdf_mem_cmp(&mac_addr, &priv->mac_addr, sizeof(mac_addr))) {
+		hdd_err("mis match of mac addr from call-back");
+		status = -EINVAL;
+		goto out;
+	}
+
+	*rcpi_value = adapter->rcpi.rcpi;
+	hdd_debug("RCPI = %d", *rcpi_value);
+out:
+	qdf_mem_free(rcpi_req);
+	hdd_request_put(request);
+
+	EXIT();
+	return status;
+}
+
+int wlan_hdd_get_rcpi(struct hdd_adapter *adapter, uint8_t *mac,
+		      int32_t *rcpi_value,
+		      enum rcpi_measurement_type measurement_type)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __wlan_hdd_get_rcpi(adapter, mac, rcpi_value, measurement_type);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}

+ 17 - 0
core/hdd/src/wlan_hdd_stats.h

@@ -300,5 +300,22 @@ void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx,
  */
 void wlan_hdd_cfg80211_link_layer_stats_ext_callback(tHddHandle ctx,
 						     tSirLLStatsResults *rsp);
+
+/**
+ * wlan_hdd_get_rcpi() - Wrapper to get current RCPI
+ * @adapter: adapter upon which the measurement is requested
+ * @mac: peer addr for which measurement is requested
+ * @rcpi_value: pointer to where the RCPI should be returned
+ * @measurement_type: type of rcpi measurement
+ *
+ * This is a wrapper function for getting RCPI, invoke this function only
+ * when rcpi support is enabled in firmware
+ *
+ * Return: 0 for success, non-zero for failure
+ */
+int wlan_hdd_get_rcpi(struct hdd_adapter *adapter, uint8_t *mac,
+		      int32_t *rcpi_value,
+		      enum rcpi_measurement_type measurement_type);
+
 #endif /* end #if !defined(WLAN_HDD_STATS_H) */
 

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

@@ -7659,6 +7659,24 @@ struct get_arp_stats_params {
 	uint32_t vdev_id;
 };
 
+typedef void (*sme_rcpi_callback)(void *context, struct qdf_mac_addr mac_addr,
+				  int32_t rcpi, QDF_STATUS status);
+/**
+ * struct sme_rcpi_req - structure for querying rcpi info
+ * @session_id: session for which rcpi is required
+ * @measurement_type: type of measurement from enum rcpi_measurement_type
+ * @rcpi_callback: callback function to be invoked for rcpi response
+ * @rcpi_context: context info for rcpi callback
+ * @mac_addr: peer addr for which rcpi is required
+ */
+struct sme_rcpi_req {
+	uint32_t session_id;
+	enum rcpi_measurement_type measurement_type;
+	sme_rcpi_callback rcpi_callback;
+	void *rcpi_context;
+	struct qdf_mac_addr mac_addr;
+};
+
 /*
  * @SCAN_REJECT_DEFAULT: default value
  * @CONNECTION_IN_PROGRESS: connection is in progress

+ 2 - 0
core/mac/src/include/sir_params.h

@@ -643,6 +643,8 @@ typedef struct sSirMbMsgP2p {
 #define SIR_HAL_SET_PER_ROAM_CONFIG_CMD     (SIR_HAL_ITC_MSG_TYPES_BEGIN + 371)
 #define SIR_HAL_RX_CHN_STATUS_EVENT         (SIR_HAL_ITC_MSG_TYPES_BEGIN + 372)
 
+#define SIR_HAL_GET_RCPI_REQ                (SIR_HAL_ITC_MSG_TYPES_BEGIN + 373)
+
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
 #define SIR_HAL_LL_STATS_EXT_SET_THRESHOLD  (SIR_HAL_ITC_MSG_TYPES_BEGIN + 378)
 #endif

+ 1 - 0
core/mac/src/sys/legacy/src/utils/src/mac_trace.c

@@ -689,6 +689,7 @@ uint8_t *mac_trace_get_wma_msg_string(uint16_t wma_msg)
 		CASE_RETURN_STRING(WMA_SET_WISA_PARAMS);
 		CASE_RETURN_STRING(WMA_SET_WOW_PULSE_CMD);
 		CASE_RETURN_STRING(WMA_SET_PER_ROAM_CONFIG_CMD);
+		CASE_RETURN_STRING(WMA_GET_RCPI_REQ);
 		CASE_RETURN_STRING(WMA_SET_DBS_SCAN_SEL_CONF_PARAMS);
 	default:
 		return (uint8_t *) "UNKNOWN";

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

@@ -1603,6 +1603,17 @@ QDF_STATUS sme_set_reorder_timeout(tHalHandle hal,
 QDF_STATUS sme_set_rx_set_blocksize(tHalHandle hal,
 		struct sir_peer_set_rx_blocksize *req);
 
+/**
+ * sme_get_rcpi() - gets the rcpi value for peer mac addr
+ * @hal: handle returned by mac_open
+ * @rcpi: rcpi request containing peer mac addr, callback and related info
+ *
+ * This function posts the rcpi measurement request message to wma queue
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_get_rcpi(tHalHandle hal, struct sme_rcpi_req *rcpi);
+
 /*
  * sme_set_chip_pwr_save_fail_cb() - set chip power save failure callback
  * @hal: global hal handle

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

@@ -15831,6 +15831,43 @@ QDF_STATUS sme_set_dbs_scan_selection_config(tHalHandle hal,
 	return status;
 }
 
+QDF_STATUS sme_get_rcpi(tHalHandle hal, struct sme_rcpi_req *rcpi)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	tpAniSirGlobal pMac = PMAC_STRUCT(hal);
+	struct scheduler_msg msg;
+	struct sme_rcpi_req *rcpi_req;
+
+	rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req));
+	if (rcpi_req == NULL) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+			  "%s: Not able to allocate memory for rcpi req",
+			  __func__);
+		return QDF_STATUS_E_NOMEM;
+	}
+	qdf_mem_copy(rcpi_req, rcpi, sizeof(*rcpi_req));
+
+	status = sme_acquire_global_lock(&pMac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		msg.bodyptr = rcpi_req;
+		msg.type = WMA_GET_RCPI_REQ;
+		status = scheduler_post_msg(QDF_MODULE_ID_WMA, &msg);
+		sme_release_global_lock(&pMac->sme);
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+				  FL("post get rcpi req failed"));
+			status = QDF_STATUS_E_FAILURE;
+			qdf_mem_free(rcpi_req);
+		}
+	} else {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+			  FL("sme_acquire_global_lock failed"));
+		qdf_mem_free(rcpi_req);
+	}
+
+	return status;
+}
+
 void sme_store_pdev(tHalHandle hal, struct wlan_objmgr_pdev *pdev)
 {
 	tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);

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

@@ -1038,6 +1038,7 @@ typedef struct {
  * @arp_offload_req: cached arp offload request
  * @ns_offload_req: cached ns offload request
  * @wow_stats: stat counters for WoW related events
+ * @rcpi_req: rcpi request
  * It stores parameters per vdev in wma.
  * @in_bmps : Whether bmps for this interface has been enabled
  * @vdev_start_wakelock: wakelock to protect vdev start op with firmware
@@ -1118,6 +1119,7 @@ struct wma_txrx_node {
 	tSirHostOffloadReq ns_offload_req;
 	bool is_vdev_valid;
 	struct sir_vdev_wow_stats wow_stats;
+	struct sme_rcpi_req *rcpi_req;
 #ifdef WLAN_FEATURE_11AX
 	bool he_capable;
 	uint32_t he_ops;
@@ -1572,6 +1574,7 @@ typedef struct {
 	bool dfs_cac_offload;
 	tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb;
 	tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb;
+	bool rcpi_enabled;
 	tSirLLStatsResults *link_stats_results;
 	uint64_t tx_fail_cnt;
 #ifdef WLAN_FEATURE_11AX

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

@@ -1231,6 +1231,27 @@ static inline void wma_sta_kickout_event(uint32_t kickout_reason,
 };
 #endif /* FEATURE_WLAN_DIAG_SUPPORT */
 
+/**
+ * wma_get_rcpi_req() - get rcpi request
+ * @handle: wma handle
+ * @rcpi_request: rcpi params
+ *
+ * Return: none
+ */
+QDF_STATUS wma_get_rcpi_req(WMA_HANDLE handle,
+			    struct sme_rcpi_req *rcpi_request);
+
+/**
+ * wma_rcpi_event_handler() - rcpi event handler
+ * @handle: wma handle
+ * @cmd_param_info: data from event
+ * @len: length
+ *
+ * Return: 0 for success or error code
+ */
+int wma_rcpi_event_handler(void *handle, uint8_t *cmd_param_info,
+			   uint32_t len);
+
 /**
  * wma_acquire_wakelock() - acquire the given wakelock
  * @wl: the wakelock to acquire

+ 2 - 0
core/wma/inc/wma_tgt_cfg.h

@@ -158,6 +158,7 @@ struct wma_dfs_radar_ind {
  * @he_cap: HE capability received from FW
  * @dfs_cac_offload: dfs and cac timer offloaded
  * @tx_bfee_8ss_enabled: Tx Beamformee support for 8x8
+ * @rcpi_enabled: for checking rcpi support
  * @fw_mem_dump_enabled: Fw memory dump support
  */
 struct wma_tgt_cfg {
@@ -193,6 +194,7 @@ struct wma_tgt_cfg {
 #endif
 	bool dfs_cac_offload;
 	bool tx_bfee_8ss_enabled;
+	bool rcpi_enabled;
 	bool fw_mem_dump_enabled;
 };
 #endif /* WMA_TGT_CFG_H */

+ 1 - 0
core/wma/inc/wma_types.h

@@ -470,6 +470,7 @@
 #define WMA_SEND_FREQ_RANGE_CONTROL_IND      SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND
 #define WMA_ENCRYPT_DECRYPT_MSG              SIR_HAL_ENCRYPT_DECRYPT_MSG
 #define WMA_POWER_DEBUG_STATS_REQ            SIR_HAL_POWER_DEBUG_STATS_REQ
+#define WMA_GET_RCPI_REQ                     SIR_HAL_GET_RCPI_REQ
 
 #define WMA_SET_DBS_SCAN_SEL_CONF_PARAMS     SIR_HAL_SET_DBS_SCAN_SEL_PARAMS
 

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

@@ -4949,6 +4949,14 @@ void wma_delete_bss_ho_fail(tp_wma_handle wma, tpDeleteBssParams params)
 		qdf_mem_free(iface->psnr_req);
 		iface->psnr_req = NULL;
 	}
+
+	if (iface->rcpi_req) {
+		struct sme_rcpi_req *rcpi_req = iface->rcpi_req;
+
+		iface->rcpi_req = NULL;
+		qdf_mem_free(rcpi_req);
+	}
+
 	qdf_mem_zero(&iface->ns_offload_req,
 			sizeof(iface->ns_offload_req));
 	qdf_mem_zero(&iface->arp_offload_req,
@@ -5109,6 +5117,13 @@ void wma_delete_bss(tp_wma_handle wma, tpDeleteBssParams params)
 		iface->psnr_req = NULL;
 	}
 
+	if (iface->rcpi_req) {
+		struct sme_rcpi_req *rcpi_req = iface->rcpi_req;
+
+		iface->rcpi_req = NULL;
+		qdf_mem_free(rcpi_req);
+	}
+
 	if (wlan_op_mode_ibss == cdp_get_opmode(soc, txrx_vdev))
 		wma->ibss_started = 0;
 

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

@@ -3845,6 +3845,12 @@ QDF_STATUS wma_wmi_service_close(void)
 			wma_handle->interfaces[i].psnr_req = NULL;
 		}
 
+		if (wma_handle->interfaces[i].rcpi_req) {
+			qdf_mem_free(wma_handle->
+				     interfaces[i].rcpi_req);
+			wma_handle->interfaces[i].rcpi_req = NULL;
+		}
+
 		wma_vdev_deinit(&wma_handle->interfaces[i]);
 	}
 
@@ -4840,6 +4846,7 @@ static void wma_update_hdd_cfg(tp_wma_handle wma_handle)
 	tgt_cfg.ap_arpns_support = wma_handle->ap_arpns_support;
 	tgt_cfg.bpf_enabled = wma_handle->bpf_enabled;
 	tgt_cfg.dfs_cac_offload = wma_handle->dfs_cac_offload;
+	tgt_cfg.rcpi_enabled = wma_handle->rcpi_enabled;
 	wma_update_ra_rate_limit(wma_handle, &tgt_cfg);
 	wma_update_hdd_band_cap(wma_handle->phy_capability, &tgt_cfg);
 	tgt_cfg.fine_time_measurement_cap =
@@ -5225,6 +5232,21 @@ int wma_rx_service_ready_event(void *handle, uint8_t *cmd_param_info,
 		return -EINVAL;
 	}
 
+	if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
+				   WMI_SERVICE_RCPI_SUPPORT)) {
+		/* register for rcpi response event */
+		status = wmi_unified_register_event_handler(
+							wma_handle->wmi_handle,
+							WMI_UPDATE_RCPI_EVENTID,
+							wma_rcpi_event_handler,
+							WMA_RX_SERIALIZER_CTX);
+		if (status) {
+			WMA_LOGE("Failed to register RCPI event handler");
+			return -EINVAL;
+		}
+		wma_handle->rcpi_enabled = true;
+	}
+
 	/* mac_id is replaced with pdev_id in converged firmware to have
 	 * multi-radio support. In order to maintain backward compatibility
 	 * with old fw, host needs to check WMI_SERVICE_DEPRECATED_REPLACE
@@ -7934,6 +7956,11 @@ static QDF_STATUS wma_mc_process_msg(struct scheduler_msg *msg)
 	case SIR_HAL_POWER_DEBUG_STATS_REQ:
 		wma_process_power_debug_stats_req(wma_handle);
 		break;
+	case WMA_GET_RCPI_REQ:
+		wma_get_rcpi_req(wma_handle,
+				 (struct sme_rcpi_req *)msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
 	case WMA_SET_WOW_PULSE_CMD:
 		wma_send_wow_pulse_cmd(wma_handle,
 			(struct wow_pulse_mode *)msg->bodyptr);

+ 117 - 0
core/wma/src/wma_utils.c

@@ -4569,6 +4569,123 @@ QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id)
 	return status;
 }
 
+QDF_STATUS wma_get_rcpi_req(WMA_HANDLE handle,
+			    struct sme_rcpi_req *rcpi_request)
+{
+	tp_wma_handle wma_handle = (tp_wma_handle) handle;
+	struct rcpi_req  cmd = {0};
+	struct wma_txrx_node *iface;
+	struct sme_rcpi_req *node_rcpi_req;
+
+	WMA_LOGD("%s: Enter", __func__);
+	iface = &wma_handle->interfaces[rcpi_request->session_id];
+	/* command is in progress */
+	if (iface->rcpi_req != NULL) {
+		WMA_LOGE("%s : previous rcpi request is pending", __func__);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	node_rcpi_req = qdf_mem_malloc(sizeof(*node_rcpi_req));
+	if (!node_rcpi_req) {
+		WMA_LOGE("Failed to allocate memory for rcpi_request");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	*node_rcpi_req = *rcpi_request;
+	iface->rcpi_req = node_rcpi_req;
+
+	cmd.vdev_id = rcpi_request->session_id;
+	qdf_mem_copy(cmd.mac_addr, &rcpi_request->mac_addr, QDF_MAC_ADDR_SIZE);
+
+	switch (rcpi_request->measurement_type) {
+
+	case RCPI_MEASUREMENT_TYPE_AVG_MGMT:
+		cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_AVG_MGMT;
+		break;
+
+	case RCPI_MEASUREMENT_TYPE_AVG_DATA:
+		cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_AVG_DATA;
+		break;
+
+	case RCPI_MEASUREMENT_TYPE_LAST_MGMT:
+		cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_LAST_MGMT;
+		break;
+
+	case RCPI_MEASUREMENT_TYPE_LAST_DATA:
+		cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_LAST_DATA;
+		break;
+
+	default:
+		/*
+		 * invalid rcpi measurement type, fall back to
+		 * RCPI_MEASUREMENT_TYPE_AVG_MGMT
+		 */
+		cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_AVG_MGMT;
+		break;
+	}
+
+	if (wmi_unified_send_request_get_rcpi_cmd(wma_handle->wmi_handle,
+						  &cmd)) {
+		WMA_LOGE("%s: Failed to send WMI_REQUEST_RCPI_CMDID",
+			 __func__);
+		iface->rcpi_req = NULL;
+		qdf_mem_free(node_rcpi_req);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	WMA_LOGD("%s: Exit", __func__);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+int wma_rcpi_event_handler(void *handle, uint8_t *cmd_param_info,
+			    uint32_t len)
+{
+	struct rcpi_res res = {0};
+	struct sme_rcpi_req *rcpi_req;
+	struct qdf_mac_addr qdf_mac;
+	struct wma_txrx_node *iface;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	tp_wma_handle wma_handle = (tp_wma_handle)handle;
+
+	status = wmi_extract_rcpi_response_event(wma_handle->wmi_handle,
+						 cmd_param_info, &res);
+	if (status == QDF_STATUS_E_INVAL)
+		return -EINVAL;
+
+	iface = &wma_handle->interfaces[res.vdev_id];
+	if (!iface->rcpi_req) {
+		WMI_LOGE("rcpi_req buffer not available");
+		return 0;
+	}
+
+	rcpi_req = iface->rcpi_req;
+	if (!rcpi_req->rcpi_callback) {
+		iface->rcpi_req = NULL;
+		qdf_mem_free(rcpi_req);
+		return 0;
+	}
+
+	if ((res.measurement_type == RCPI_MEASUREMENT_TYPE_INVALID) ||
+	    (res.vdev_id != rcpi_req->session_id) ||
+	    (res.measurement_type != rcpi_req->measurement_type) ||
+	    (qdf_mem_cmp(res.mac_addr, &rcpi_req->mac_addr,
+			 QDF_MAC_ADDR_SIZE))) {
+		WMI_LOGE("invalid rcpi_response");
+		iface->rcpi_req = NULL;
+		qdf_mem_free(rcpi_req);
+		return 0;
+	}
+
+	qdf_mem_copy(&qdf_mac, res.mac_addr, QDF_MAC_ADDR_SIZE);
+	(rcpi_req->rcpi_callback)(rcpi_req->rcpi_context, qdf_mac,
+				  res.rcpi_value, status);
+	iface->rcpi_req = NULL;
+	qdf_mem_free(rcpi_req);
+
+	return 0;
+}
+
 bool wma_is_service_enabled(WMI_SERVICE service_type)
 {
 	tp_wma_handle wma;