diff --git a/Kbuild b/Kbuild index c512116bbd..3410ecae6d 100644 --- a/Kbuild +++ b/Kbuild @@ -4573,6 +4573,8 @@ endif cppflags-$(CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET) += -DWLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET +ccflags-$(CONFIG_SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND) += -DSHUTDOWN_WLAN_IN_SYSTEM_SUSPEND + ifeq ($(CONFIG_WLAN_FEATURE_MCC_QUOTA), y) cppflags-y += -DWLAN_FEATURE_MCC_QUOTA ifdef CONFIG_WLAN_MCC_MIN_CHANNEL_QUOTA diff --git a/components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h b/components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h index d820335e84..e4e8f5f514 100644 --- a/components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h +++ b/components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h @@ -340,13 +340,14 @@ * * gSuspendMode - Suspend mode configuration * @Min: 0 - * @Max: 2 + * @Max: 3 * @Default: 2 * * This ini is used to set suspend mode. Configurations are as follows: * 0 - Does not support suspend. * 1 - Legency suspend mode, PDEV suspend. * 2 - WOW suspend mode. + * 3 - Shutdown wlan while suspend. * * Related: None * @@ -357,7 +358,7 @@ * */ #define CFG_PMO_SUSPEND_MODE CFG_INI_UINT("gSuspendMode", \ - 0, 2, 2, \ + 0, 3, 2, \ CFG_VALUE_OR_DEFAULT, \ "Suspend mode") diff --git a/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h b/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h index 45e6d2c26f..5bca2e2379 100644 --- a/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h +++ b/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h @@ -175,7 +175,7 @@ enum powersave_mode { * @PMO_SUSPEND_NONE: Does not support suspend * @PMO_SUSPEND_LEGENCY: Legency PDEV suspend mode * @PMO_SUSPEND_WOW: WoW suspend mode - * @PMO_SUSPEND_SHUTDOWN: shutdown while suspend mode + * @PMO_SUSPEND_SHUTDOWN: Shutdown suspend mode. Shutdown while suspend */ enum pmo_suspend_mode { PMO_SUSPEND_NONE = 0, diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 87e45b93e1..250593f026 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1710,6 +1710,7 @@ enum wlan_state_ctrl_str_id { * @dump_in_progress: Stores value of dump in progress * @hdd_dual_sta_policy: Concurrent STA policy configuration * @is_wlan_disabled: if wlan is disabled by userspace + * @pm_notifier: PM notifier of hdd modules */ struct hdd_context { struct wlan_objmgr_psoc *psoc; @@ -1889,6 +1890,7 @@ struct hdd_context { /* Present state of driver cds modules */ enum driver_modules_status driver_status; struct qdf_delayed_work psoc_idle_timeout_work; + struct notifier_block pm_notifier; struct acs_dfs_policy acs_policy; uint16_t wmi_max_len; struct suspend_resume_stats suspend_resume_stats; diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 4e715657c9..0ce10065bd 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -83,6 +83,7 @@ #include #include #include +#include #ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH #include "qdf_periodic_work.h" @@ -9395,6 +9396,79 @@ out: return ret; } +#ifdef SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND +static QDF_STATUS +hdd_shutdown_wlan_in_suspend_prepare(struct hdd_context *hdd_ctx) +{ +#define SHUTDOWN_IN_SUSPEND_RETRY 10 + + int count = 0; + + if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) != PMO_SUSPEND_SHUTDOWN) { + hdd_debug("shutdown in suspend not supported"); + return 0; + } + + while (hdd_is_any_interface_open(hdd_ctx) && + count < SHUTDOWN_IN_SUSPEND_RETRY) { + count++; + hdd_debug_rl("sleep 50ms to wait adapters stopped, #%d", count); + msleep(50); + } + if (count >= SHUTDOWN_IN_SUSPEND_RETRY) { + hdd_err("some adapters not stopped"); + return -EBUSY; + } + + hdd_debug("call pld idle shutdown directly"); + return pld_idle_shutdown(hdd_ctx->parent_dev, hdd_psoc_idle_shutdown); +} + +static int hdd_pm_notify(struct notifier_block *b, + unsigned long event, void *p) +{ + struct hdd_context *hdd_ctx = container_of(b, struct hdd_context, + pm_notifier); + + if (wlan_hdd_validate_context(hdd_ctx) != 0) + return NOTIFY_STOP; + + hdd_debug("got PM event: %lu", event); + + switch (event) { + case PM_SUSPEND_PREPARE: + case PM_HIBERNATION_PREPARE: + if (0 != hdd_shutdown_wlan_in_suspend_prepare(hdd_ctx)) + return NOTIFY_STOP; + break; + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + break; + } + + return NOTIFY_DONE; +} + +static void hdd_pm_notifier_init(struct hdd_context *hdd_ctx) +{ + hdd_ctx->pm_notifier.notifier_call = hdd_pm_notify; + register_pm_notifier(&hdd_ctx->pm_notifier); +} + +static void hdd_pm_notifier_deinit(struct hdd_context *hdd_ctx) +{ + unregister_pm_notifier(&hdd_ctx->pm_notifier); +} +#else +static inline void hdd_pm_notifier_init(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_pm_notifier_deinit(struct hdd_context *hdd_ctx) +{ +} +#endif + /** * hdd_context_deinit() - Deinitialize HDD context * @hdd_ctx: HDD context. @@ -9438,6 +9512,7 @@ void hdd_context_destroy(struct hdd_context *hdd_ctx) hdd_ctx->config = NULL; cfg_release(); + hdd_pm_notifier_deinit(hdd_ctx); qdf_delayed_work_destroy(&hdd_ctx->psoc_idle_timeout_work); wiphy_free(hdd_ctx->wiphy); } @@ -12631,6 +12706,8 @@ struct hdd_context *hdd_context_create(struct device *dev) goto wiphy_dealloc; } + hdd_pm_notifier_init(hdd_ctx); + hdd_ctx->parent_dev = dev; hdd_ctx->last_scan_reject_vdev_id = WLAN_UMAC_VDEV_ID_MAX;