diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index e3e339945772..188bc3b81c99 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/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; diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index a99e23f6207e..8d9cbd6a3f95 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/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; +} diff --git a/core/hdd/src/wlan_hdd_hostapd.h b/core/hdd/src/wlan_hdd_hostapd.h index d40c65aa2331..45d3ccadf6eb 100644 --- a/core/hdd/src/wlan_hdd_hostapd.h +++ b/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, diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index b1ad240521c2..92eacd601d06 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/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: diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c index 9c955a03d04a..040ba7eb8823 100644 --- a/core/hdd/src/wlan_hdd_stats.c +++ b/core/hdd/src/wlan_hdd_stats.c @@ -34,6 +34,8 @@ #include "hif.h" #include #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(¶ms); + 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; +} diff --git a/core/hdd/src/wlan_hdd_stats.h b/core/hdd/src/wlan_hdd_stats.h index 0209ac003c1d..654c253ab178 100644 --- a/core/hdd/src/wlan_hdd_stats.h +++ b/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) */ diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index c83259fc3388..2186befd9b07 100644 --- a/core/mac/inc/sir_api.h +++ b/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 diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h index e0f077f81b76..adbd6ceaec4b 100644 --- a/core/mac/src/include/sir_params.h +++ b/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 diff --git a/core/mac/src/sys/legacy/src/utils/src/mac_trace.c b/core/mac/src/sys/legacy/src/utils/src/mac_trace.c index bb473165734a..30c5db071033 100644 --- a/core/mac/src/sys/legacy/src/utils/src/mac_trace.c +++ b/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"; diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 76de33117009..09c401ba5c4b 100644 --- a/core/sme/inc/sme_api.h +++ b/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 diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index be2f0cdca8f1..bda81287ae50 100644 --- a/core/sme/src/common/sme_api.c +++ b/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); diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 2dd2648ff947..45fa64f147d8 100644 --- a/core/wma/inc/wma.h +++ b/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 diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 2c0f506231d7..9692b3588823 100644 --- a/core/wma/inc/wma_internal.h +++ b/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 diff --git a/core/wma/inc/wma_tgt_cfg.h b/core/wma/inc/wma_tgt_cfg.h index 3a82c8bfe0f0..134e3765cb78 100644 --- a/core/wma/inc/wma_tgt_cfg.h +++ b/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 */ diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h index 710a3689523d..312ef4b5cf31 100644 --- a/core/wma/inc/wma_types.h +++ b/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 diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c index 61b91faf421d..930e1011d539 100644 --- a/core/wma/src/wma_dev_if.c +++ b/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; diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 4480e7f60343..d8aca4ce0ba6 100644 --- a/core/wma/src/wma_main.c +++ b/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); diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index ac05274043df..2b2319f3d246 100644 --- a/core/wma/src/wma_utils.c +++ b/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;