From a2a82c280d35cb15d57be68fa9bc0d05ca2a4ccb Mon Sep 17 00:00:00 2001 From: Yu Ouyang Date: Sun, 29 May 2022 22:13:09 +0800 Subject: [PATCH] qcacld-3.0: Idle shutdown in suspend prepare To support shutdown WLAN when system goes into suspend, add idle shutdown when got PM_SUSPEND_PREPARE/PM_HIBERNATION_PREPARE. Before suspend/shutdown, user space should stop adapter. And after resume, user space should restart adapter. This can ensure user and kernel space to sync adapter's state. Change-Id: Id1f5172a7fc1792c83c8c1c20127de815f7e4980 CRs-Fixed: 3208931 --- .../pmo/dispatcher/inc/wlan_pmo_common_cfg.h | 5 +- .../inc/wlan_pmo_common_public_struct.h | 4 +- core/hdd/inc/wlan_hdd_main.h | 1 + core/hdd/src/wlan_hdd_main.c | 57 +++++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) 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;