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 2d95ebf753..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,11 +175,13 @@ 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 suspend mode. Shutdown while suspend
*/
enum pmo_suspend_mode {
PMO_SUSPEND_NONE = 0,
PMO_SUSPEND_LEGENCY,
- PMO_SUSPEND_WOW
+ PMO_SUSPEND_WOW,
+ PMO_SUSPEND_SHUTDOWN
};
#define PMO_TARGET_SUSPEND_TIMEOUT (4000)
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index 9cd547f85d..fb534e4ef1 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -2253,6 +2253,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;
bool rps;
bool dynamic_rps;
bool enable_rxthread;
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index c287276a5f..ed9120075a 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -84,6 +84,7 @@
#include
#include
#include
+#include
#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH
#include "qdf_periodic_work.h"
@@ -9821,6 +9822,7 @@ void hdd_context_destroy(struct hdd_context *hdd_ctx)
hdd_ctx->config = NULL;
cfg_release();
+ unregister_pm_notifier(&hdd_ctx->pm_notifier);
qdf_delayed_work_destroy(&hdd_ctx->psoc_idle_timeout_work);
wiphy_free(hdd_ctx->wiphy);
}
@@ -13618,6 +13620,58 @@ static inline QDF_STATUS hdd_cfg_parse_connection_roaming_cfg(void)
}
#endif
+static QDF_STATUS hdd_shutdown_wlan_in_suspend_prepare(void)
+{
+#define SHUTDOWN_IN_SUSPEND_RETRY 10
+
+ int count = 0;
+ struct hdd_context *hdd_ctx;
+
+ hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+ if (wlan_hdd_validate_context(hdd_ctx) != 0)
+ return -EINVAL;
+
+ if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) != PMO_SUSPEND_SHUTDOWN) {
+ hdd_info("shutdown in suspend not supported");
+ return 0;
+ }
+
+ while (hdd_is_any_interface_open(hdd_ctx) &&
+ count < SHUTDOWN_IN_SUSPEND_RETRY) {
+ count++;
+ hdd_info_rl("sleep 50ms to wait apdaters stopped, #%d", count);
+ msleep(50);
+ }
+ if (count >= SHUTDOWN_IN_SUSPEND_RETRY) {
+ hdd_err("some adapters not stopped");
+ return -EBUSY;
+ }
+
+ qdf_delayed_work_stop_sync(&hdd_ctx->psoc_idle_timeout_work);
+
+ 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)
+{
+ hdd_info("got PM event: %lu", event);
+
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ case PM_HIBERNATION_PREPARE:
+ if (0 != hdd_shutdown_wlan_in_suspend_prepare())
+ return NOTIFY_STOP;
+ break;
+ case PM_POST_SUSPEND:
+ case PM_POST_HIBERNATION:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
struct hdd_context *hdd_context_create(struct device *dev)
{
QDF_STATUS status;
@@ -13640,6 +13694,9 @@ struct hdd_context *hdd_context_create(struct device *dev)
goto wiphy_dealloc;
}
+ hdd_ctx->pm_notifier.notifier_call = hdd_pm_notify;
+ register_pm_notifier(&hdd_ctx->pm_notifier);
+
hdd_ctx->parent_dev = dev;
hdd_ctx->last_scan_reject_vdev_id = WLAN_UMAC_VDEV_ID_MAX;