diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 2e4ab9664211..fc82548811db 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -92,6 +92,7 @@ #include #include #include "wlan_hdd_nud_tracking.h" +#include "wlan_hdd_twt.h" /* * Preprocessor definitions and constants @@ -1908,6 +1909,9 @@ struct hdd_context { /* defining the board related information */ uint32_t hw_bd_id; struct board_info hw_bd_info; +#ifdef WLAN_FEATURE_TWT + enum twt_status twt_state; +#endif }; /** diff --git a/core/hdd/inc/wlan_hdd_twt.h b/core/hdd/inc/wlan_hdd_twt.h index a4d48d4ee162..728b7e436cbb 100644 --- a/core/hdd/inc/wlan_hdd_twt.h +++ b/core/hdd/inc/wlan_hdd_twt.h @@ -26,10 +26,44 @@ #if !defined(WLAN_HDD_TWT_H) #define WLAN_HDD_TWT_H +#include "qdf_types.h" +#include "qdf_status.h" + struct hdd_context; struct wma_tgt_cfg; +struct wmi_twt_enable_complete_event_param; #ifdef WLAN_FEATURE_TWT +/** + * enum twt_status - TWT target state + * @TWT_INIT: Init State + * @TWT_DISABLED: TWT is disabled + * @TWT_FW_TRIGGER_ENABLE_REQUESTED: FW triggered enable requested + * @TWT_FW_TRIGGER_ENABLED: FW triggered twt enabled + * @TWT_HOST_TRIGGER_ENABLE_REQUESTED: Host triggered TWT requested + * @TWT_HOST_TRIGGER_ENABLED: Host triggered TWT enabled + * @TWT_DISABLE_REQUESTED: TWT disable requested + * @TWT_SUSPEND_REQUESTED: TWT suspend requested + * @TWT_SUSPENDED: Successfully suspended TWT + * @TWT_RESUME_REQUESTED: TWT Resume requested + * @TWT_RESUMED: Successfully resumed TWT + * @TWT_CLOSED: Deinitialized TWT feature and closed + */ +enum twt_status { + TWT_INIT, + TWT_DISABLED, + TWT_FW_TRIGGER_ENABLE_REQUESTED, + TWT_FW_TRIGGER_ENABLED, + TWT_HOST_TRIGGER_ENABLE_REQUESTED, + TWT_HOST_TRIGGER_ENABLED, + TWT_DISABLE_REQUESTED, + TWT_SUSPEND_REQUESTED, + TWT_SUSPENDED, + TWT_RESUME_REQUESTED, + TWT_RESUMED, + TWT_CLOSED, +}; + /** * hdd_twt_print_ini_config() - Print TWT INI config items * @hdd_ctx: HDD Context @@ -56,6 +90,46 @@ void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx, */ void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx); +/** + * hdd_twt_enable_comp_cb() - TWT enable complete event callback + * @hdd_ctx: pointer to global HDD Context + * @twt_event: TWT event data received from the target + * + * Return: None + */ +void hdd_twt_enable_comp_cb(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params); + +/** + * hdd_twt_disable_comp_cb() - TWT disable complete event callback + * @hdd_ctx: pointer to global HDD Context + * + * Return: None + */ +void hdd_twt_disable_comp_cb(void *hdd_ctx); + +/** + * wlan_hdd_twt_init() - Initialize TWT + * @hdd_ctx: pointer to global HDD Context + * + * Initialize the TWT feature by registering the callbacks + * with the lower layers. + * + * Return: None + */ +void wlan_hdd_twt_init(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_twt_deinit() - Deinitialize TWT + * @hdd_ctx: pointer to global HDD Context + * + * Deinitialize the TWT feature by deregistering the + * callbacks with the lower layers. + * + * Return: None + */ +void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx); + #else static inline void hdd_twt_print_ini_config(struct hdd_context *hdd_ctx) { @@ -70,5 +144,22 @@ static inline void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx) { } +static inline void hdd_twt_enable_comp_cb(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params) +{ +} + +static inline void hdd_twt_disable_comp_cb(void *hdd_ctx) +{ +} + +static inline void wlan_hdd_twt_init(struct hdd_context *hdd_ctx) +{ +} + +static inline void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx) +{ +} + #endif #endif /* if !defined(WLAN_HDD_TWT_H)*/ diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 7676f60ff67d..66d6a1d19d6a 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -2007,7 +2007,6 @@ void hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg) hdd_update_tgt_he_cap(hdd_ctx, cfg); } hdd_update_tgt_twt_cap(hdd_ctx, cfg); - hdd_send_twt_enable_cmd(hdd_ctx); hdd_update_vdev_nss(hdd_ctx); @@ -10228,6 +10227,7 @@ static int hdd_features_init(struct hdd_context *hdd_ctx) goto deregister_cb; wlan_hdd_init_chan_info(hdd_ctx); + wlan_hdd_twt_init(hdd_ctx); hdd_exit(); return 0; @@ -10248,6 +10248,7 @@ deregister_cb: */ static void hdd_features_deinit(struct hdd_context *hdd_ctx) { + wlan_hdd_twt_deinit(hdd_ctx); wlan_hdd_deinit_chan_info(hdd_ctx); wlan_hdd_tsf_deinit(hdd_ctx); } diff --git a/core/hdd/src/wlan_hdd_twt.c b/core/hdd/src/wlan_hdd_twt.c index effcdb47f4e2..646f9ab04ff3 100644 --- a/core/hdd/src/wlan_hdd_twt.c +++ b/core/hdd/src/wlan_hdd_twt.c @@ -79,3 +79,91 @@ void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx) wma_send_twt_enable_cmd(pdev_id, congestion_timeout); } +void hdd_twt_enable_comp_cb(void *hddctx, + struct wmi_twt_enable_complete_event_param *params) +{ + struct hdd_context *hdd_ctx = hddctx; + enum twt_status prev_state; + + if (!hdd_ctx) { + hdd_err("TWT: Invalid HDD Context"); + return; + } + prev_state = hdd_ctx->twt_state; + if (params->status == WMI_HOST_ENABLE_TWT_STATUS_OK || + params->status == WMI_HOST_ENABLE_TWT_STATUS_ALREADY_ENABLED) { + switch (prev_state) { + case TWT_FW_TRIGGER_ENABLE_REQUESTED: + hdd_ctx->twt_state = TWT_FW_TRIGGER_ENABLED; + break; + case TWT_HOST_TRIGGER_ENABLE_REQUESTED: + hdd_ctx->twt_state = TWT_HOST_TRIGGER_ENABLED; + break; + default: + break; + } + } + if (params->status == WMI_HOST_ENABLE_TWT_INVALID_PARAM || + params->status == WMI_HOST_ENABLE_TWT_STATUS_UNKNOWN_ERROR) + hdd_ctx->twt_state = TWT_INIT; + + hdd_debug("TWT: pdev ID:%d, status:%d State transitioned from %d to %d", + params->pdev_id, params->status, + prev_state, hdd_ctx->twt_state); +} + +void hdd_twt_disable_comp_cb(void *hddctx) +{ + struct hdd_context *hdd_ctx = hddctx; + enum twt_status prev_state; + + if (!hdd_ctx) { + hdd_err("TWT: Invalid HDD Context"); + return; + } + prev_state = hdd_ctx->twt_state; + hdd_ctx->twt_state = TWT_DISABLED; + + hdd_debug("TWT: State transitioned from %d to %d", + prev_state, hdd_ctx->twt_state); +} + +void wlan_hdd_twt_init(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + hdd_ctx->twt_state = TWT_INIT; + status = sme_register_twt_enable_complete_cb(hdd_ctx->hHal, + hdd_twt_enable_comp_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Register twt enable complete failed"); + return; + } + + status = sme_register_twt_disable_complete_cb(hdd_ctx->hHal, + hdd_twt_disable_comp_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Register twt disable complete failed"); + goto twt_init_fail; + } + hdd_send_twt_enable_cmd(hdd_ctx); + return; + +twt_init_fail: + + sme_deregister_twt_enable_complete_cb(hdd_ctx->hHal); +} + +void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + status = sme_deregister_twt_disable_complete_cb(hdd_ctx->hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("De-register of twt disable cb failed: %d", status); + status = sme_deregister_twt_enable_complete_cb(hdd_ctx->hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("De-register of twt enable cb failed: %d", status); + + hdd_ctx->twt_state = TWT_CLOSED; +} diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 728d0c880d89..6117fda894e8 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -2336,4 +2336,68 @@ void sme_set_amsdu(tHalHandle hal, bool enable); uint8_t sme_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags, uint8_t nss, uint8_t *mcs_rate_flags); +#ifdef WLAN_FEATURE_TWT +/** + * sme_register_twt_enable_complete_cb() - TWT enable registrar + * @hal: HAL handle + * @twt_enable_cb: Function callback to handle enable event + * @hdd_ctx: Global HDD Context + * + * Return: QDF Status + */ +QDF_STATUS sme_register_twt_enable_complete_cb(tHalHandle hal, + void (*twt_enable_cb)(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params)); + +/** + * sme_register_twt_disable_complete_cb - TWT disable registrar + * @hal: HAL handle + * @twt_disable_cb: Function callback to handle disable event + * + * Return: QDF Status + */ +QDF_STATUS sme_register_twt_disable_complete_cb(tHalHandle hal, + void (*twt_disable_cb)(void *hdd_ctx)); + +/** + * sme_deregister_twt_enable_complete_cb() - TWT enable deregistrar + * @hal: HAL handle + * + * Return: QDF Status + */ +QDF_STATUS sme_deregister_twt_enable_complete_cb(tHalHandle hal); + +/** + * sme_deregister_twt_disable_complete_cb - TWT disable deregistrar + * @hal: HAL handle + * + * Return: QDF Status + */ +QDF_STATUS sme_deregister_twt_disable_complete_cb(tHalHandle hal); + +#else +static inline QDF_STATUS sme_register_twt_enable_complete_cb(tHalHandle hal, + void (*twt_enable_cb)(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params)) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_register_twt_disable_complete_cb(tHalHandle hal, + void (*twt_disable_cb)(void *hdd_ctx)) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_deregister_twt_enable_complete_cb(tHalHandle hal) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_deregister_twt_disable_complete_cb(tHalHandle hal) +{ + return QDF_STATUS_SUCCESS; +} +#endif + #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index 8cf2db600e9f..df6b6642fffc 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -36,7 +36,7 @@ #include "host_diag_core_event.h" #include "csr_link_list.h" #include "sme_power_save.h" - +struct wmi_twt_enable_complete_event_param; /*-------------------------------------------------------------------------- Type declarations ------------------------------------------------------------------------*/ @@ -256,6 +256,9 @@ typedef struct tagSmeStruct { void (*tx_queue_cb)(void *, uint32_t vdev_id, enum netif_action_type action, enum netif_reason_type reason); + void (*twt_enable_cb)(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params); + void (*twt_disable_cb)(void *hdd_ctx); } tSmeStruct, *tpSmeStruct; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index bce3e21f8d10..75ec3556f8c9 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -15536,6 +15536,55 @@ QDF_STATUS sme_deregister_tx_queue_cb(tHalHandle hal) return sme_register_tx_queue_cb(hal, NULL); } +#ifdef WLAN_FEATURE_TWT +QDF_STATUS sme_register_twt_enable_complete_cb(tHalHandle hal, + void (*twt_enable_cb)(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params)) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.twt_enable_cb = twt_enable_cb; + sme_release_global_lock(&mac->sme); + sme_debug("TWT: enable callback set"); + } else { + sme_err("Aquiring lock failed %d", status); + } + + return status; +} + +QDF_STATUS sme_register_twt_disable_complete_cb(tHalHandle hal, + void (*twt_disable_cb)(void *hdd_ctx)) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.twt_disable_cb = twt_disable_cb; + sme_release_global_lock(&mac->sme); + sme_debug("TWT: disable callback set"); + } else { + sme_err("Aquiring lock failed %d", status); + } + + return status; +} + +QDF_STATUS sme_deregister_twt_enable_complete_cb(tHalHandle hal) +{ + return sme_register_twt_enable_complete_cb(hal, NULL); +} + +QDF_STATUS sme_deregister_twt_disable_complete_cb(tHalHandle hal) +{ + return sme_register_twt_disable_complete_cb(hal, NULL); +} +#endif + QDF_STATUS sme_set_smps_cfg(uint32_t vdev_id, uint32_t param_id, uint32_t param_val) { diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 052b7117fd7e..15ece44d5498 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -1355,4 +1355,6 @@ int wma_vdev_bss_color_collision_info_handler(void *handle, uint8_t *event, uint32_t len); +int wma_twt_en_complete_event_handler(void *handle, + uint8_t *event, uint32_t len); #endif diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index c58d32e3c579..7543038a47bb 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -3564,6 +3564,13 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, wma_vdev_bss_color_collision_info_handler, WMA_RX_WORK_CTX); +#ifdef WLAN_FEATURE_TWT + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_twt_enable_complete_event_id, + wma_twt_en_complete_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif + return QDF_STATUS_SUCCESS; diff --git a/core/wma/src/wma_twt.c b/core/wma/src/wma_twt.c index 04af9c253975..5aa9b69e21a5 100644 --- a/core/wma/src/wma_twt.c +++ b/core/wma/src/wma_twt.c @@ -24,6 +24,8 @@ #include "wma_twt.h" #include "wmi_unified_twt_api.h" +#include "wma_internal.h" +#include "wmi_unified_priv.h" void wma_send_twt_enable_cmd(uint32_t pdev_id, uint32_t congestion_timeout) { @@ -39,3 +41,34 @@ void wma_send_twt_enable_cmd(uint32_t pdev_id, uint32_t congestion_timeout) WMA_LOGE("Failed to enable TWT"); } +int wma_twt_en_complete_event_handler(void *handle, + uint8_t *event, uint32_t len) +{ + struct wmi_twt_enable_complete_event_param param; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_unified_t wmi_handle; + tpAniSirGlobal mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE); + int status = -EINVAL; + + if (!wma_handle) { + WMA_LOGE("Invalid wma handle for TWT complete"); + return status; + } + wmi_handle = (wmi_unified_t)wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE("Invalid wmi handle for TWT complete"); + return status; + } + if (wmi_handle->ops->extract_twt_enable_comp_event) + status = wmi_handle->ops->extract_twt_enable_comp_event( + wmi_handle, + event, + ¶m); + WMA_LOGD("TWT: Received TWT enable comp event, status:%d", status); + + if (mac->sme.twt_enable_cb) + mac->sme.twt_enable_cb(mac->hHdd, ¶m); + + return status; +} +