diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index d265901b0760..c83346e71eea 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1051,10 +1051,7 @@ struct hdd_adapter_s { #ifdef WLAN_FEATURE_TSF /* tsf value received from firmware */ - uint32_t tsf_low; - uint32_t tsf_high; - /* TSF capture state */ - enum hdd_tsf_capture_state tsf_state; + uint64_t cur_target_time; uint64_t tsf_sync_soc_timer; #endif @@ -1620,6 +1617,14 @@ struct hdd_context_s { /* Lock to control access to dnbs and coex avoid freq list */ struct mutex avoid_freq_lock; #endif +#ifdef WLAN_FEATURE_TSF + /* indicate whether tsf has been initialized */ + qdf_atomic_t tsf_ready_flag; + /* indicate whether it's now capturing tsf(updating tstamp-pair) */ + qdf_atomic_t cap_tsf_flag; + /* the context that is capturing tsf */ + hdd_adapter_t *cap_tsf_context; +#endif }; /** diff --git a/core/hdd/inc/wlan_hdd_tsf.h b/core/hdd/inc/wlan_hdd_tsf.h index cdb3890120d4..645fcb5c689f 100644 --- a/core/hdd/inc/wlan_hdd_tsf.h +++ b/core/hdd/inc/wlan_hdd_tsf.h @@ -38,6 +38,7 @@ * @TSF_GET_FAIL: get fail * @TSF_RESET_GPIO_FAIL: GPIO reset fail * @TSF_SAP_NOT_STARTED_NO_TSF SAP not started + * @TSF_NOT_READY: TSF module is not initialized or init failed */ enum hdd_tsf_get_state { TSF_RETURN = 0, @@ -47,7 +48,8 @@ enum hdd_tsf_get_state { TSF_CAPTURE_FAIL, TSF_GET_FAIL, TSF_RESET_GPIO_FAIL, - TSF_SAP_NOT_STARTED_NO_TSF + TSF_SAP_NOT_STARTED_NO_TSF, + TSF_NOT_READY }; /** @@ -61,19 +63,81 @@ enum hdd_tsf_capture_state { }; #ifdef WLAN_FEATURE_TSF +/** + * wlan_hdd_tsf_init() - set gpio and callbacks for + * capturing tsf and init tsf_plus + * @hdd_ctx: pointer to the hdd_context_t + * + * This function set the callback to sme module, the callback will be + * called when a tsf event is reported by firmware; set gpio number + * to FW, FW will toggle this gpio when received a CAP_TSF command; + * do tsf_plus init + * + * Return: nothing + */ void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx); + +/** + * wlan_hdd_tsf_deinit() - reset callbacks for capturing tsf, deinit tsf_plus + * @hdd_ctx: pointer to the hdd_context_t + * + * This function reset the callback to sme module, and deinit tsf_plus + * + * Return: nothing + */ +void wlan_hdd_tsf_deinit(hdd_context_t *hdd_ctx); + +/** + * hdd_capture_tsf() - capture tsf + * @adapter: pointer to adapter + * @buf: pointer to uplayer buf + * @len : the length of buf + * + * This function returns tsf value to uplayer. + * + * Return: 0 for success or non-zero negative failure code + */ int hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len); + +/** + * hdd_indicate_tsf() - return tsf to uplayer + * + * @adapter: pointer to adapter + * @buf: pointer to uplayer buf + * @len : the length of buf + * + * This function returns tsf value to uplayer. + * + * Return: Describe the execute result of this routine + */ int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len); + +/** + * wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Handle TSF SET / GET operation from userspace + * + * Return: 0 on success, negative errno on failure + */ int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); + int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf); #else static inline void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx) { } +static inline void wlan_hdd_tsf_deinit(hdd_context_t *hdd_ctx) +{ +} + static inline int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len) { diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 18354be274e3..d4ef349b8c7d 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -8483,35 +8483,6 @@ static void hdd_initialize_mac_address(hdd_context_t *hdd_ctx) } } -/** - * hdd_tsf_init() - Initialize the TSF synchronization interface - * @hdd_ctx: HDD global context - * - * When TSF synchronization via GPIO is supported by the driver and - * has been enabled in the configuration file, this function plumbs - * the GPIO value down to firmware via SME. - * - * Return: None - */ -#ifdef WLAN_FEATURE_TSF -static void hdd_tsf_init(hdd_context_t *hdd_ctx) -{ - QDF_STATUS status; - - if (hdd_ctx->config->tsf_gpio_pin == TSF_GPIO_PIN_INVALID) - return; - - status = sme_set_tsf_gpio(hdd_ctx->hHal, - hdd_ctx->config->tsf_gpio_pin); - if (!QDF_IS_STATUS_SUCCESS(status)) - hdd_err("Set tsf GPIO failed, status: %d", status); -} -#else -static void hdd_tsf_init(hdd_context_t *hdd_ctx) -{ -} -#endif - static int hdd_set_smart_chainmask_enabled(hdd_context_t *hdd_ctx) { int vdev_id = 0; @@ -8899,7 +8870,7 @@ static int hdd_features_init(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter) if (!QDF_IS_STATUS_SUCCESS(status)) hdd_err("Error setting txlimit in sme: %d", status); - hdd_tsf_init(hdd_ctx); + wlan_hdd_tsf_init(hdd_ctx); ret = hdd_register_cb(hdd_ctx); if (ret) { @@ -8945,9 +8916,21 @@ out: } +/** + * hdd_features_deinit() - Deinit features + * @hdd_ctx: HDD context + * + * De-Initialize features and their feature context. + * + * Return: none. + */ +static void hdd_features_deinit(hdd_context_t *hdd_ctx) +{ + wlan_hdd_tsf_deinit(hdd_ctx); +} + #ifdef NAPIER_SCAN /** - * * hdd_post_cds_enable_config() - HDD post cds start config helper * @adapter - Pointer to the HDD * @@ -9055,6 +9038,10 @@ static int hdd_deconfigure_cds(hdd_context_t *hdd_ctx) int ret = 0; ENTER(); + + /* De-init features */ + hdd_features_deinit(hdd_ctx); + /* De-register the SME callbacks */ hdd_deregister_cb(hdd_ctx); diff --git a/core/hdd/src/wlan_hdd_tsf.c b/core/hdd/src/wlan_hdd_tsf.c index aadd77568f90..92fb5057c3b4 100644 --- a/core/hdd/src/wlan_hdd_tsf.c +++ b/core/hdd/src/wlan_hdd_tsf.c @@ -36,72 +36,65 @@ static struct completion tsf_sync_get_completion_evt; #define WLAN_TSF_SYNC_GET_TIMEOUT 2000 + /** - * hdd_capture_tsf() - capture tsf - * @adapter: pointer to adapter - * @buf: pointer to uplayer buf - * @len : the length of buf + * enum hdd_tsf_op_result - result of tsf operation * - * This function returns tsf value to uplayer. - * - * Return: 0 for success or non-zero negative failure code + * HDD_TSF_OP_SUCC: succeed + * HDD_TSF_OP_FAIL: fail */ -int hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len) +enum hdd_tsf_op_result { + HDD_TSF_OP_SUCC, + HDD_TSF_OP_FAIL +}; + +static +enum hdd_tsf_get_state hdd_tsf_check_conn_state(hdd_adapter_t *adapter) { - int ret = 0; + enum hdd_tsf_get_state ret = TSF_RETURN; hdd_station_ctx_t *hdd_sta_ctx; - if (adapter == NULL || buf == NULL) { - hdd_err("invalid pointer"); - return -EINVAL; - } - if (len != 1) - return -EINVAL; - - /* Reset TSF value for new capture */ - adapter->tsf_high = 0; - adapter->tsf_low = 0; - adapter->tsf_sync_soc_timer = 0; - if (adapter->device_mode == QDF_STA_MODE || - adapter->device_mode == QDF_P2P_CLIENT_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) { hdd_err("failed to cap tsf, not connect with ap"); - buf[0] = TSF_STA_NOT_CONNECTED_NO_TSF; - return ret; + ret = TSF_STA_NOT_CONNECTED_NO_TSF; } - } - if ((adapter->device_mode == QDF_SAP_MODE || - adapter->device_mode == QDF_P2P_GO_MODE) && - !(test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags))) { + } else if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + !(test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags))) { hdd_err("Soft AP / P2p GO not beaconing"); - buf[0] = TSF_SAP_NOT_STARTED_NO_TSF; - return ret; - } - if (adapter->tsf_state == TSF_CAP_STATE) { - hdd_err("current in capture state, pls reset"); - buf[0] = TSF_CURRENT_IN_CAP_STATE; - } else { - hdd_info("Send TSF capture to FW"); - buf[0] = TSF_RETURN; - adapter->tsf_state = TSF_CAP_STATE; - init_completion(&tsf_sync_get_completion_evt); - ret = wma_cli_set_command((int)adapter->sessionId, - (int)GEN_PARAM_CAPTURE_TSF, - adapter->sessionId, - GEN_CMD); - - if (ret != QDF_STATUS_SUCCESS) { - hdd_err("capture fail"); - buf[0] = TSF_CAPTURE_FAIL; - adapter->tsf_state = TSF_IDLE; - } + ret = TSF_SAP_NOT_STARTED_NO_TSF; } return ret; } +static bool hdd_tsf_is_initialized(hdd_adapter_t *adapter) +{ + hdd_context_t *hddctx; + + if (!adapter) { + hdd_err("invalid adapter"); + return false; + } + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return false; + } + + if (!qdf_atomic_read(&hddctx->tsf_ready_flag)) { + hdd_err("TSF is not initialized"); + return false; + } + + return true; +} + /** * hdd_tsf_reset_gpio() - Reset TSF GPIO used for host timer sync * @adapter: pointer to adapter @@ -136,60 +129,137 @@ static int hdd_tsf_reset_gpio(struct hdd_adapter_s *adapter) } #endif -/** - * hdd_indicate_tsf() - return tsf to uplayer - * @adapter: pointer to adapter - * @buf: pointer to uplayer buf - * @len : the length of buf - * - * This function returns tsf value to upper layer. - * - * Return: 0 for success or non-zero negative failure code - */ -int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len) +static enum hdd_tsf_op_result hdd_capture_tsf_internal( + hdd_adapter_t *adapter, uint32_t *buf, int len) { - hdd_station_ctx_t *hdd_sta_ctx; + int ret; + hdd_context_t *hddctx; if (adapter == NULL || buf == NULL) { hdd_err("invalid pointer"); - return -EINVAL; + return HDD_TSF_OP_FAIL; + } + + if (len != 1) + return HDD_TSF_OP_FAIL; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return HDD_TSF_OP_FAIL; + } + + if (!hdd_tsf_is_initialized(adapter)) { + buf[0] = TSF_NOT_READY; + return HDD_TSF_OP_SUCC; + } + + buf[0] = hdd_tsf_check_conn_state(adapter); + if (buf[0] != TSF_RETURN) + return HDD_TSF_OP_SUCC; + + if (qdf_atomic_inc_return(&hddctx->cap_tsf_flag) > 1) { + hdd_err("current in capture state"); + buf[0] = TSF_CURRENT_IN_CAP_STATE; + return HDD_TSF_OP_SUCC; + } + + /* record adapter for cap_tsf_irq_handler */ + hddctx->cap_tsf_context = adapter; + + hdd_err("+ioctl issue cap tsf cmd"); + + /* Reset TSF value for new capture */ + adapter->cur_target_time = 0; + + buf[0] = TSF_RETURN; + init_completion(&tsf_sync_get_completion_evt); + ret = wma_cli_set_command((int)adapter->sessionId, + (int)GEN_PARAM_CAPTURE_TSF, + adapter->sessionId, GEN_CMD); + if (QDF_STATUS_SUCCESS != ret) { + hdd_err("cap tsf fail"); + buf[0] = TSF_CAPTURE_FAIL; + hddctx->cap_tsf_context = NULL; + qdf_atomic_set(&hddctx->cap_tsf_flag, 0); + return HDD_TSF_OP_SUCC; + } + hdd_err("-ioctl return cap tsf cmd"); + return HDD_TSF_OP_SUCC; +} + +static enum hdd_tsf_op_result hdd_indicate_tsf_internal( + hdd_adapter_t *adapter, uint32_t *buf, int len) +{ + int ret; + hdd_context_t *hddctx; + + if (!adapter || !buf) { + hdd_err("invalid pointer"); + return HDD_TSF_OP_FAIL; } if (len != 3) - return -EINVAL; + return HDD_TSF_OP_FAIL; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return HDD_TSF_OP_FAIL; + } buf[1] = 0; buf[2] = 0; - 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) { - hdd_info("fail to get tsf, sta in disconnected"); - buf[0] = TSF_STA_NOT_CONNECTED_NO_TSF; - return 0; - } + + if (!hdd_tsf_is_initialized(adapter)) { + buf[0] = TSF_NOT_READY; + return HDD_TSF_OP_SUCC; } - if ((adapter->device_mode == QDF_SAP_MODE || - adapter->device_mode == QDF_P2P_GO_MODE) && - !(test_bit(SOFTAP_BSS_STARTED, - &adapter->event_flags))) { - hdd_err("Soft AP / P2p GO not beaconing"); - buf[0] = TSF_SAP_NOT_STARTED_NO_TSF; - return 0; - } - if (adapter->tsf_high == 0 && adapter->tsf_low == 0) { + + buf[0] = hdd_tsf_check_conn_state(adapter); + if (buf[0] != TSF_RETURN) + return HDD_TSF_OP_SUCC; + + if (adapter->cur_target_time == 0) { hdd_info("TSF value not received"); buf[0] = TSF_NOT_RETURNED_BY_FW; + return HDD_TSF_OP_SUCC; } else { - buf[0] = hdd_tsf_reset_gpio(adapter); - buf[1] = adapter->tsf_low; - buf[2] = adapter->tsf_high; - adapter->tsf_state = TSF_IDLE; + buf[0] = TSF_RETURN; + buf[1] = (uint32_t)(adapter->cur_target_time & 0xffffffff); + buf[2] = (uint32_t)((adapter->cur_target_time >> 32) & + 0xffffffff); + + if (!qdf_atomic_read(&hddctx->cap_tsf_flag)) { + hdd_info("old: status=%u, tsf_low=%u, tsf_high=%u", + buf[0], buf[1], buf[2]); + return HDD_TSF_OP_SUCC; + } + + ret = hdd_tsf_reset_gpio(adapter); + if (0 != ret) { + hdd_err("reset tsf gpio fail"); + buf[0] = TSF_RESET_GPIO_FAIL; + return HDD_TSF_OP_SUCC; + } + hddctx->cap_tsf_context = NULL; + qdf_atomic_set(&hddctx->cap_tsf_flag, 0); hdd_info("get tsf cmd,status=%u, tsf_low=%u, tsf_high=%u", buf[0], buf[1], buf[2]); + return HDD_TSF_OP_SUCC; } - return 0; +} + +int hdd_capture_tsf(hdd_adapter_t *adapter, uint32_t *buf, int len) +{ + return (hdd_capture_tsf_internal(adapter, buf, len) == + HDD_TSF_OP_SUCC) ? 0 : -EINVAL; +} + +int hdd_indicate_tsf(hdd_adapter_t *adapter, uint32_t *buf, int len) +{ + return (hdd_indicate_tsf_internal(adapter, buf, len) == + HDD_TSF_OP_SUCC) ? 0 : -EINVAL; } /** @@ -226,11 +296,17 @@ int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf) hdd_err("failed to find adapter"); return -EINVAL; } + + if (!hdd_tsf_is_initialized(adapter)) { + hdd_err("tsf is not init, ignore tsf event"); + return -EINVAL; + } + hdd_info("tsf cb handle event, device_mode is %d", adapter->device_mode); - adapter->tsf_low = ptsf->tsf_low; - adapter->tsf_high = ptsf->tsf_high; + adapter->cur_target_time = ((uint64_t)ptsf->tsf_high << 32 | + ptsf->tsf_low); adapter->tsf_sync_soc_timer = ((uint64_t) ptsf->soc_timer_high << 32 | ptsf->soc_timer_low); @@ -349,8 +425,7 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, } if (hdd_wlan_nla_put_u64(reply_skb, QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE, - ((uint64_t) adapter->tsf_high << 32 | - adapter->tsf_low)) || + adapter->cur_target_time) || hdd_wlan_nla_put_u64(reply_skb, QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE, adapter->tsf_sync_soc_timer)) { @@ -367,17 +442,6 @@ end: return status; } -/** - * wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * Handle TSF SET / GET operation from userspace - * - * Return: 0 on success, negative errno on failure - */ int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, @@ -403,5 +467,40 @@ int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, */ void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx) { - sme_set_tsfcb(hdd_ctx->hHal, hdd_get_tsf_cb, hdd_ctx); + QDF_STATUS hal_status; + + if (!hdd_ctx) + return; + + if (qdf_atomic_inc_return(&hdd_ctx->tsf_ready_flag) > 1) + return; + + qdf_atomic_init(&hdd_ctx->cap_tsf_flag); + + if (hdd_ctx->config->tsf_gpio_pin == TSF_GPIO_PIN_INVALID) + goto fail; + + hal_status = sme_set_tsf_gpio(hdd_ctx->hHal, + hdd_ctx->config->tsf_gpio_pin); + if (QDF_STATUS_SUCCESS != hal_status) { + hdd_err("set tsf GPIO failed, status: %d", hal_status); + goto fail; + } + + return; + +fail: + qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0); +} + +void wlan_hdd_tsf_deinit(hdd_context_t *hdd_ctx) +{ + if (!hdd_ctx) + return; + + if (!qdf_atomic_read(&hdd_ctx->tsf_ready_flag)) + return; + + qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0); + qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0); }