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
This commit is contained in:
Yu Ouyang
2022-05-29 22:13:09 +08:00
committed by Madan Koyyalamudi
parent f4dfc63210
commit a2a82c280d
4 changed files with 64 additions and 3 deletions

View File

@@ -340,13 +340,14 @@
* <ini>
* 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 @@
* </ini>
*/
#define CFG_PMO_SUSPEND_MODE CFG_INI_UINT("gSuspendMode", \
0, 2, 2, \
0, 3, 2, \
CFG_VALUE_OR_DEFAULT, \
"Suspend mode")

View File

@@ -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)

View File

@@ -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;

View File

@@ -84,6 +84,7 @@
#include <linux/ctype.h>
#include <linux/compat.h>
#include <linux/ethtool.h>
#include <linux/suspend.h>
#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;