diff options
| author | Rajeev Kumar Sirasanagandla <rsirasan@codeaurora.org> | 2016-11-22 21:20:33 +0530 |
|---|---|---|
| committer | qcabuildsw <qcabuildsw@localhost> | 2017-01-23 05:52:34 -0800 |
| commit | 4436532f3a45344d17c01880385f0fdc6f76d7b0 (patch) | |
| tree | 358452822bfdf148f1f8c305740b3cdc96f79eaa | |
| parent | f2b9cb54f94f6516fe0feae8bb3ce806769ab95c (diff) | |
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
| -rw-r--r-- | core/hdd/inc/wlan_hdd_main.h | 18 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_hostapd.c | 30 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_hostapd.h | 16 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_main.c | 4 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_stats.c | 245 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_stats.h | 19 | ||||
| -rw-r--r-- | core/mac/inc/sir_api.h | 19 | ||||
| -rw-r--r-- | core/mac/src/include/sir_params.h | 4 | ||||
| -rw-r--r-- | core/sme/inc/sme_api.h | 11 | ||||
| -rw-r--r-- | core/sme/src/common/sme_api.c | 37 | ||||
| -rw-r--r-- | core/wma/inc/wma.h | 3 | ||||
| -rw-r--r-- | core/wma/inc/wma_internal.h | 22 | ||||
| -rw-r--r-- | core/wma/inc/wma_tgt_cfg.h | 4 | ||||
| -rw-r--r-- | core/wma/inc/wma_types.h | 1 | ||||
| -rw-r--r-- | core/wma/src/wma_dev_if.c | 15 | ||||
| -rw-r--r-- | core/wma/src/wma_main.c | 21 | ||||
| -rw-r--r-- | core/wma/src/wma_utils.c | 159 |
17 files changed, 623 insertions, 5 deletions
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 420df191d375..83840acac954 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -151,6 +151,9 @@ #define WLAN_WAIT_TIME_BPF 1000 +/* rcpi request timeout in milli seconds */ +#define WLAN_WAIT_TIME_RCPI 500 + #define MAX_NUMBER_OF_ADAPTERS 4 #define MAX_CFG_STRING_LEN 255 @@ -337,6 +340,7 @@ extern spinlock_t hdd_context_lock; #define TEMP_CONTEXT_MAGIC 0x74656d70 /* TEMP (temperature) */ #define BPF_CONTEXT_MAGIC 0x4575354 /* BPF */ #define POWER_STATS_MAGIC 0x14111990 +#define RCPI_CONTEXT_MAGIC 0x7778888 /* RCPI */ /* MAX OS Q block time value in msec * Prevent from permanent stall, resume OS Q if timer expired */ @@ -910,6 +914,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_adapter_s { /* Magic cookie for adapter sanity verification. Note that this * needs to be at the beginning of the private data structure so @@ -1143,6 +1157,9 @@ struct hdd_adapter_s { struct power_stats_response *chip_power_stats; bool fast_roaming_allowed; + + /* rcpi information */ + struct rcpi_info rcpi; }; #define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station) @@ -1613,6 +1630,7 @@ struct hdd_context_s { scan_reject_states last_scan_reject_reason; unsigned long last_scan_reject_timestamp; uint8_t beacon_probe_rsp_cnt_per_scan; + bool rcpi_enabled; }; /*--------------------------------------------------------------------------- diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index df853039733c..6d70588ca10e 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -5863,6 +5863,10 @@ QDF_STATUS hdd_init_ap_mode(hdd_adapter_t *pAdapter) qdf_mem_free(pAdapter->sessionCtx.ap.sapConfig.acs_cfg.ch_list); qdf_mem_zero(&pAdapter->sessionCtx.ap.sapConfig.acs_cfg, sizeof(struct sap_acs_cfg)); + + /* rcpi info initialization */ + qdf_mem_zero(&pAdapter->rcpi, sizeof(pAdapter->rcpi)); + return status; error_wmm_init: @@ -8348,3 +8352,29 @@ int wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, return ret; } + +bool hdd_is_peer_associated(hdd_adapter_t *adapter, + struct qdf_mac_addr *mac_addr) +{ + uint32_t cnt = 0; + hdd_station_info_t *sta_info = NULL; + + if (!adapter || !mac_addr) { + hdd_err("Invalid adapter or mac_addr"); + return false; + } + + sta_info = adapter->aStaInfo; + spin_lock_bh(&adapter->staInfo_lock); + for (cnt = 0; cnt < WLAN_MAX_STA_COUNT; cnt++) { + if ((sta_info[cnt].isUsed) && + !qdf_mem_cmp(&(sta_info[cnt].macAddrSTA), mac_addr, + QDF_MAC_ADDR_SIZE)) + break; + } + spin_unlock_bh(&adapter->staInfo_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 251d5c7dabfb..423464741462 100644 --- a/core/hdd/src/wlan_hdd_hostapd.h +++ b/core/hdd/src/wlan_hdd_hostapd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -121,4 +121,18 @@ int wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, struct cfg80211_beacon_data *params); QDF_STATUS wlan_hdd_config_acs(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter); + +/** + * 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(hdd_adapter_t *adapter, + struct qdf_mac_addr *mac_addr); + #endif /* end #if !defined(WLAN_HDD_HOSTAPD_H) */ diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index f46ebb62e6a0..57a2a03a1c25 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -1408,6 +1408,7 @@ void hdd_update_tgt_cfg(void *context, void *param) cfg->bpf_enabled, hdd_ctx->config->bpf_packet_filter_enable); 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); hdd_ctx->fw_mem_dump_enabled = cfg->fw_mem_dump_enabled; @@ -2721,6 +2722,9 @@ QDF_STATUS hdd_init_station_mode(hdd_adapter_t *adapter) if (status != QDF_STATUS_SUCCESS) goto error_lro_enable; + /* rcpi info initialization */ + qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi)); + return QDF_STATUS_SUCCESS; error_lro_enable: diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c index fd8092334f0a..ae65a7b5950a 100644 --- a/core/hdd/src/wlan_hdd_stats.c +++ b/core/hdd/src/wlan_hdd_stats.c @@ -32,6 +32,7 @@ #include "wlan_hdd_trace.h" #include "wlan_hdd_lpass.h" #include "hif.h" +#include "wlan_hdd_hostapd.h" #ifdef WLAN_FEATURE_LINK_LAYER_STATS @@ -2561,3 +2562,247 @@ 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(hdd_adapter_t *adapter, + struct qdf_mac_addr *mac_addr, + int32_t *rcpi_value, + bool *reassoc) +{ + hdd_station_ctx_t *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_ReassocScenario) { + /* return the cached rcpi, if mac addr matches */ + hdd_info("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) +{ + hdd_adapter_t *adapter; + struct statsContext *rcpi_context; + + if (!context) { + hdd_err("No rcpi context"); + return; + } + + rcpi_context = context; + adapter = rcpi_context->pAdapter; + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid adapter magic"); + return; + } + + /* + * there is a race condition that exists between this callback + * function and the caller since the caller could time out + * either before or while this code is executing. we use a + * spinlock to serialize these actions + */ + spin_lock(&hdd_context_lock); + if (rcpi_context->magic != RCPI_CONTEXT_MAGIC) { + /* + * the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hdd_warn("Invalid RCPI context magic"); + return; + } + + rcpi_context->magic = 0; + adapter->rcpi.mac_addr = mac_addr; + if (status != QDF_STATUS_SUCCESS) + /* peer rcpi is not available for requested mac addr */ + adapter->rcpi.rcpi = 0; + else + adapter->rcpi.rcpi = rcpi; + + /* notify the caller */ + complete(&rcpi_context->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * __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(hdd_adapter_t *adapter, + uint8_t *mac, + int32_t *rcpi_value, + enum rcpi_measurement_type measurement_type) +{ + hdd_context_t *hdd_ctx; + static struct statsContext rcpi_context; + int status = 0; + unsigned long rc; + struct qdf_mac_addr mac_addr; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct sme_rcpi_req *rcpi_req; + 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_info("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; + } + + init_completion(&rcpi_context.completion); + rcpi_context.pAdapter = adapter; + rcpi_context.magic = RCPI_CONTEXT_MAGIC; + + 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 = &rcpi_context; + + qdf_status = sme_get_rcpi(hdd_ctx->hHal, rcpi_req); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("Unable to retrieve RCPI"); + status = qdf_status_to_os_return(qdf_status); + } else { + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&rcpi_context.completion, + msecs_to_jiffies(WLAN_WAIT_TIME_RCPI)); + if (!rc) { + hdd_err("SME timed out while retrieving RCPI"); + status = -EINVAL; + } + } + qdf_mem_free(rcpi_req); + + spin_lock(&hdd_context_lock); + rcpi_context.magic = 0; + spin_unlock(&hdd_context_lock); + + if (status) { + hdd_err("rcpi computation is failed"); + } else { + if (qdf_mem_cmp(&mac_addr, &adapter->rcpi.mac_addr, + sizeof(mac_addr))) { + hdd_err("mac addr is not matching from call-back"); + status = -EINVAL; + } else { + *rcpi_value = adapter->rcpi.rcpi; + hdd_info("RCPI = %d", *rcpi_value); + } + } + + EXIT(); + return status; +} + +int wlan_hdd_get_rcpi(hdd_adapter_t *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 a7f4e126f9c1..7b9bba501796 100644 --- a/core/hdd/src/wlan_hdd_stats.h +++ b/core/hdd/src/wlan_hdd_stats.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -221,5 +221,22 @@ void wlan_hdd_cfg80211_stats_ext_callback(void *ctx, void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx, int indType, void *pRsp); + +/** + * 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(hdd_adapter_t *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 e51a17ccc80b..52753a94dae6 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -6883,4 +6883,23 @@ struct udp_resp_offload { char udp_payload_filter[MAX_LEN_UDP_RESP_OFFLOAD]; char udp_response_payload[MAX_LEN_UDP_RESP_OFFLOAD]; }; + +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; +}; + #endif /* __SIR_API_H */ diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h index 4bbedbf8c043..affb1642b172 100644 --- a/core/mac/src/include/sir_params.h +++ b/core/mac/src/include/sir_params.h @@ -648,7 +648,9 @@ typedef struct sSirMbMsgP2p { #define SIR_HAL_SET_PER_ROAM_CONFIG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 371) -#define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) +#define SIR_HAL_GET_RCPI_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 372) + +#define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) /* CFG message types */ #define SIR_CFG_MSG_TYPES_BEGIN (SIR_CFG_MODULE_ID << 8) diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 18ba9210ab29..96414ad96e81 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1420,4 +1420,15 @@ static inline QDF_STATUS sme_set_udp_resp_offload(struct udp_resp_offload } #endif +/** + * 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); + #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 835b7beb004e..0b1022c5d71b 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -17159,3 +17159,40 @@ QDF_STATUS sme_set_udp_resp_offload(struct udp_resp_offload *pudp_resp_cmd) return status; } #endif + +QDF_STATUS sme_get_rcpi(tHalHandle hal, struct sme_rcpi_req *rcpi) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + cds_msg_t cds_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)) { + cds_msg.bodyptr = rcpi_req; + cds_msg.type = WMA_GET_RCPI_REQ; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &cds_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; +} diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 3e8f9aaf2c4e..e19cb126e95d 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -1014,6 +1014,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. */ struct wma_txrx_node { @@ -1093,6 +1094,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; }; #if defined(QCA_WIFI_FTM) @@ -1604,6 +1606,7 @@ typedef struct { bool sub_20_support; 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; bool fw_mem_dump_enabled; tSirAddonPsReq ps_setting; diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 74da22868058..ecd31a487f4a 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -1236,4 +1236,26 @@ void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id, int32_t rssi); int wma_unified_power_debug_stats_event_handler(void *handle, uint8_t *cmd_param_info, uint32_t len); + +/** + * 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); + #endif diff --git a/core/wma/inc/wma_tgt_cfg.h b/core/wma/inc/wma_tgt_cfg.h index c92ac0834c42..9a6dca599087 100644 --- a/core/wma/inc/wma_tgt_cfg.h +++ b/core/wma/inc/wma_tgt_cfg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -150,6 +150,7 @@ struct wma_dfs_radar_ind { * @nan_datapath_enabled: nan data path support * @bool is_ra_rate_limit_enabled: RA filter support * @fw_mem_dump_enabled: Fw memory dump support + * @rcpi_enabled: for checking rcpi support */ struct wma_tgt_cfg { uint32_t target_fw_version; @@ -180,5 +181,6 @@ struct wma_tgt_cfg { bool sub_20_support; uint16_t wmi_max_len; bool fw_mem_dump_enabled; + bool rcpi_enabled; }; #endif /* WMA_TGT_CFG_H */ diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h index 064699ab6098..a417e33b6f42 100644 --- a/core/wma/inc/wma_types.h +++ b/core/wma/inc/wma_types.h @@ -484,6 +484,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_WOW_PULSE_CMD SIR_HAL_SET_WOW_PULSE_CMD diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c index 809c17a067f4..605f2660f59f 100644 --- a/core/wma/src/wma_dev_if.c +++ b/core/wma/src/wma_dev_if.c @@ -4461,6 +4461,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, @@ -4574,6 +4582,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 == ol_txrx_get_opmode(txrx_vdev)) wma->ibss_started = 0; diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index bdcb55be5c69..302617f2242b 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -4278,6 +4278,7 @@ static void wma_update_hdd_cfg(tp_wma_handle wma_handle) #endif /* WLAN_FEATURE_LPSS */ tgt_cfg.ap_arpns_support = wma_handle->ap_arpns_support; tgt_cfg.bpf_enabled = wma_handle->bpf_enabled; + tgt_cfg.rcpi_enabled = wma_handle->rcpi_enabled; wma_update_ra_rate_limit(wma_handle, &tgt_cfg); tgt_cfg.fine_time_measurement_cap = wma_handle->fine_time_measurement_cap; @@ -4711,6 +4712,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 @@ -7095,6 +7111,11 @@ QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg) (struct wow_pulse_mode *)msg->bodyptr); qdf_mem_free(msg->bodyptr); break; + case WMA_GET_RCPI_REQ: + wma_get_rcpi_req(wma_handle, + (struct sme_rcpi_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; default: WMA_LOGD("unknown msg type %x", msg->type); /* Do Nothing? MSG Body should be freed at here */ diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index b9ff00e835c3..582cbd342284 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -3810,3 +3810,160 @@ bool wma_is_p2p_lo_capable(void) return false; } + +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 = NULL; + + 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->session_id = rcpi_request->session_id; + node_rcpi_req->measurement_type = rcpi_request->measurement_type; + node_rcpi_req->rcpi_callback = rcpi_request->rcpi_callback; + node_rcpi_req->rcpi_context = rcpi_request->rcpi_context; + node_rcpi_req->mac_addr = rcpi_request->mac_addr; + 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_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) +{ + WMI_UPDATE_RCPI_EVENTID_param_tlvs *param_buf; + wmi_update_rcpi_event_fixed_param *event; + struct sme_rcpi_req *rcpi_req; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + struct qdf_mac_addr qdf_mac; + struct wma_txrx_node *iface; + enum rcpi_measurement_type msmt_type; + QDF_STATUS rcpi_status = QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = (tp_wma_handle)handle; + + param_buf = (WMI_UPDATE_RCPI_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid rcpi event", __func__); + return -EINVAL; + } + + event = param_buf->fixed_param; + iface = &wma->interfaces[event->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; + } + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, mac_addr); + + switch (event->measurement_type) { + case WMI_RCPI_MEASUREMENT_TYPE_AVG_MGMT: + msmt_type = RCPI_MEASUREMENT_TYPE_AVG_MGMT; + break; + + case WMI_RCPI_MEASUREMENT_TYPE_AVG_DATA: + msmt_type = RCPI_MEASUREMENT_TYPE_AVG_DATA; + break; + + case WMI_RCPI_MEASUREMENT_TYPE_LAST_MGMT: + msmt_type = RCPI_MEASUREMENT_TYPE_LAST_MGMT; + break; + + case WMI_RCPI_MEASUREMENT_TYPE_LAST_DATA: + msmt_type = RCPI_MEASUREMENT_TYPE_LAST_DATA; + break; + + default: + WMI_LOGE("Invalid rcpi measurement type from firmware"); + rcpi_status = QDF_STATUS_E_INVAL; + break; + } + + + if (!QDF_IS_STATUS_SUCCESS(rcpi_status) || + (event->vdev_id != rcpi_req->session_id) || + (msmt_type != rcpi_req->measurement_type) || + (qdf_mem_cmp(mac_addr, &rcpi_req->mac_addr, QDF_MAC_ADDR_SIZE))) { + WMI_LOGE("invalid rcpi_req for specified rcpi_req"); + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + return 0; + } + + qdf_mem_copy(&qdf_mac, mac_addr, QDF_MAC_ADDR_SIZE); + + if (event->status) + status = QDF_STATUS_E_FAILURE; + else + status = QDF_STATUS_SUCCESS; + + (rcpi_req->rcpi_callback)(rcpi_req->rcpi_context, qdf_mac, event->rcpi, + status); + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + + return 0; +} |
