diff --git a/Kbuild b/Kbuild index cb9c620bdf..92b997052f 100644 --- a/Kbuild +++ b/Kbuild @@ -2690,6 +2690,10 @@ endif #normally, TDLS negative behavior is not needed cppflags-$(CONFIG_QCOM_TDLS) += -DFEATURE_WLAN_TDLS +ifeq ($(CONFIG_LITHIUM), y) +cppflags-$(CONFIG_QCOM_TDLS) += -DTDLS_WOW_ENABLED +endif + cppflags-$(CONFIG_WLAN_GET_TDLS_PEERS) += -DWLAN_GET_TDLS_PEERS cppflags-$(CONFIG_WLAN_SET_RANGE_EXT) += -DWLAN_SET_RANGE_EXT diff --git a/components/tdls/core/src/wlan_tdls_main.h b/components/tdls/core/src/wlan_tdls_main.h index 973e5816c0..6cefca524e 100644 --- a/components/tdls/core/src/wlan_tdls_main.h +++ b/components/tdls/core/src/wlan_tdls_main.h @@ -165,6 +165,7 @@ struct tdls_set_state_info { * @tdls_external_peer_count: external tdls peer count * @tdls_nss_switch_in_progress: tdls antenna switch in progress * @tdls_nss_teardown_complete: tdls tear down complete + * @tdls_disable_in_progress: tdls is disable in progress * @tdls_nss_transition_mode: tdls nss transition mode * @tdls_teardown_peers_cnt: tdls tear down peer count * @set_state_info: set tdls state info @@ -182,6 +183,11 @@ struct tdls_set_state_info { * @tdls_update_dp_vdev_flags store CDP_UPDATE_TDLS_FLAGS * @tdls_idle_peer_data: provide information about idle peer * @tdls_ct_spinlock: connection tracker spin lock + * @is_prevent_suspend: prevent suspend or not + * @is_drv_supported: platform supports drv or not, enable/disable tdls wow + * based on this flag. + * @wake_lock: wake lock + * @runtime_lock: runtime lock * @tdls_osif_init_cb: Callback to initialize the tdls private * @tdls_osif_deinit_cb: Callback to deinitialize the tdls private */ @@ -224,6 +230,12 @@ struct tdls_soc_priv_obj { uint16_t tdls_del_all_peers; uint32_t tdls_update_dp_vdev_flags; qdf_spinlock_t tdls_ct_spinlock; +#ifdef TDLS_WOW_ENABLED + bool is_prevent_suspend; + bool is_drv_supported; + qdf_wake_lock_t wake_lock; + qdf_runtime_lock_t runtime_lock; +#endif tdls_vdev_init_cb tdls_osif_init_cb; tdls_vdev_deinit_cb tdls_osif_deinit_cb; }; diff --git a/components/tdls/core/src/wlan_tdls_peer.c b/components/tdls/core/src/wlan_tdls_peer.c index 241924a057..43ce1e8d8d 100644 --- a/components/tdls/core/src/wlan_tdls_peer.c +++ b/components/tdls/core/src/wlan_tdls_peer.c @@ -27,6 +27,7 @@ #include #include #include "wlan_reg_ucfg_api.h" +#include static uint8_t calculate_hash_key(const uint8_t *macaddr) { @@ -552,6 +553,84 @@ void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param, peer->supported_oper_classes[i]; } +#ifdef TDLS_WOW_ENABLED +/** + * tdls_prevent_suspend(): Prevent suspend for TDLS + * + * Acquire wake lock and prevent suspend for TDLS + * + * Return None + */ +static void tdls_prevent_suspend(struct tdls_soc_priv_obj *tdls_soc) +{ + if (tdls_soc->is_prevent_suspend) + return; + + qdf_wake_lock_acquire(&tdls_soc->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_TDLS); + qdf_runtime_pm_prevent_suspend(&tdls_soc->runtime_lock); + tdls_soc->is_prevent_suspend = true; +} + +/** + * tdls_allow_suspend(): Allow suspend for TDLS + * + * Release wake lock and allow suspend for TDLS + * + * Return None + */ +static void tdls_allow_suspend(struct tdls_soc_priv_obj *tdls_soc) +{ + if (!tdls_soc->is_prevent_suspend) + return; + + qdf_wake_lock_release(&tdls_soc->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_TDLS); + qdf_runtime_pm_allow_suspend(&tdls_soc->runtime_lock); + tdls_soc->is_prevent_suspend = false; +} + +/** + * tdls_update_pmo_status() - Update PMO status by TDLS status + * @tdls_vdev: TDLS vdev object + * @old_status: old link status + * @new_status: new link status + * + * Return: None. + */ +static void tdls_update_pmo_status(struct tdls_vdev_priv_obj *tdls_vdev, + enum tdls_link_state old_status, + enum tdls_link_state new_status) +{ + struct tdls_soc_priv_obj *tdls_soc; + + tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev); + if (!tdls_soc) { + tdls_err("NULL psoc object"); + return; + } + + if (tdls_soc->is_drv_supported) + return; + + if ((old_status < TDLS_LINK_CONNECTING) && + (new_status == TDLS_LINK_CONNECTING)) + tdls_prevent_suspend(tdls_soc); + + if ((old_status > TDLS_LINK_IDLE) && + (new_status == TDLS_LINK_IDLE) && + (!tdls_soc->connected_peer_count) && + (!tdls_is_progress(tdls_vdev, NULL, 0))) + tdls_allow_suspend(tdls_soc); +} +#else +static void tdls_update_pmo_status(struct tdls_vdev_priv_obj *tdls_vdev, + enum tdls_link_state old_status, + enum tdls_link_state new_status) +{ +} +#endif + /** * tdls_set_link_status() - set link statue for TDLS peer * @vdev_obj: TDLS vdev object @@ -572,6 +651,7 @@ void tdls_set_link_status(struct tdls_vdev_priv_obj *vdev_obj, uint32_t channel = 0; struct tdls_peer *peer; struct tdls_soc_priv_obj *soc_obj; + enum tdls_link_state old_status; peer = tdls_find_peer(vdev_obj, mac); if (!peer) { @@ -580,7 +660,9 @@ void tdls_set_link_status(struct tdls_vdev_priv_obj *vdev_obj, return; } + old_status = peer->link_status; peer->link_status = link_status; + tdls_update_pmo_status(vdev_obj, old_status, link_status); if (link_status >= TDLS_LINK_DISCOVERED) peer->discovery_attempt = 0; @@ -612,11 +694,16 @@ void tdls_set_peer_link_status(struct tdls_peer *peer, uint32_t channel = 0; struct tdls_soc_priv_obj *soc_obj; struct tdls_vdev_priv_obj *vdev_obj; + enum tdls_link_state old_status; tdls_debug("state %d reason %d peer:" QDF_MAC_ADDR_STR, link_status, link_reason, QDF_MAC_ADDR_ARRAY(peer->peer_mac.bytes)); + + vdev_obj = peer->vdev_priv; + old_status = peer->link_status; peer->link_status = link_status; + tdls_update_pmo_status(vdev_obj, old_status, link_status); if (link_status >= TDLS_LINK_DISCOVERED) peer->discovery_attempt = 0; @@ -624,7 +711,6 @@ void tdls_set_peer_link_status(struct tdls_peer *peer, if (peer->is_forced_peer && peer->state_change_notification) { peer->reason = link_reason; - vdev_obj = peer->vdev_priv; soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); if (!soc_obj) { tdls_err("NULL psoc object"); diff --git a/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c index 077ca3f016..07b5d06c3c 100644 --- a/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c +++ b/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c @@ -224,9 +224,50 @@ static QDF_STATUS tdls_object_init_params( return QDF_STATUS_SUCCESS; } +#ifdef TDLS_WOW_ENABLED +/** + * tdls_wow_init(): Create/init wake lock for TDLS + * + * Create/init wake lock for TDLS if DVR isn't supported + * + * Return None + */ +static void tdls_wow_init(struct tdls_soc_priv_obj *soc_obj) +{ + soc_obj->is_prevent_suspend = false; + soc_obj->is_drv_supported = qdf_is_drv_supported(); + if (!soc_obj->is_drv_supported) { + qdf_wake_lock_create(&soc_obj->wake_lock, "wlan_tdls"); + qdf_runtime_lock_init(&soc_obj->runtime_lock); + } +} + +/** + * tdls_wow_deinit(): Destroy/deinit wake lock for TDLS + * + * Destroy/deinit wake lock for TDLS if DVR isn't supported + * + * Return None + */ +static void tdls_wow_deinit(struct tdls_soc_priv_obj *soc_obj) +{ + if (!soc_obj->is_drv_supported) { + qdf_runtime_lock_deinit(&soc_obj->runtime_lock); + qdf_wake_lock_destroy(&soc_obj->wake_lock); + } +} +#else +static void tdls_wow_init(struct tdls_soc_priv_obj *soc_obj) +{ +} + +static void tdls_wow_deinit(struct tdls_soc_priv_obj *soc_obj) +{ +} +#endif + static QDF_STATUS tdls_global_init(struct tdls_soc_priv_obj *soc_obj) { - tdls_object_init_params(soc_obj); soc_obj->connected_peer_count = 0; soc_obj->tdls_nss_switch_in_progress = false; @@ -238,13 +279,16 @@ static QDF_STATUS tdls_global_init(struct tdls_soc_priv_obj *soc_obj) soc_obj->tdls_disable_in_progress = false; qdf_spinlock_create(&soc_obj->tdls_ct_spinlock); + tdls_wow_init(soc_obj); return QDF_STATUS_SUCCESS; } static QDF_STATUS tdls_global_deinit(struct tdls_soc_priv_obj *soc_obj) { + tdls_wow_deinit(soc_obj); qdf_spinlock_destroy(&soc_obj->tdls_ct_spinlock); + return QDF_STATUS_SUCCESS; }