qcacld-3.0: Add the Full Power Down feature support

Add the support for the feature of Full Power Down while
in low power mode.
For this feature, it need to power down wlan chip when
suspend, and power up wlan chip when resume, so need to
change to call wlan driver shutdown and then power off the
wlan chip instead of calling wlan driver suspend when do
suspend, and changing to do power on wlan chip, download
wlan firmware, and calling wlan driver reinit instead of
calling wlan driver resume when do resume.

Change-Id: I293647175c151da0fd6628345f98ea65c83b1bb3
CRs-Fixed: 3061366
This commit is contained in:
Ke Huang
2021-10-25 17:07:18 +08:00
committed by Gerrit - the friendly Code Review server
parent ba6acfde12
commit b43015863f
13 changed files with 215 additions and 8 deletions

4
Kbuild
View File

@@ -4169,6 +4169,10 @@ endif
cppflags-$(CONFIG_DP_FT_LOCK_HISTORY) += -DDP_FT_LOCK_HISTORY cppflags-$(CONFIG_DP_FT_LOCK_HISTORY) += -DDP_FT_LOCK_HISTORY
ifeq ($(CONFIG_WLAN_FULL_POWER_DOWN), y)
cppflags-y += -DFEATURE_WLAN_FULL_POWER_DOWN_SUPPORT
endif
ccflags-$(CONFIG_INTRA_BSS_FWD_OFFLOAD) += -DINTRA_BSS_FWD_OFFLOAD ccflags-$(CONFIG_INTRA_BSS_FWD_OFFLOAD) += -DINTRA_BSS_FWD_OFFLOAD
ccflags-$(CONFIG_GET_DRIVER_MODE) += -DFEATURE_GET_DRIVER_MODE ccflags-$(CONFIG_GET_DRIVER_MODE) += -DFEATURE_GET_DRIVER_MODE

View File

@@ -340,13 +340,14 @@
* <ini> * <ini>
* gSuspendMode - Suspend mode configuration * gSuspendMode - Suspend mode configuration
* @Min: 0 * @Min: 0
* @Max: 2 * @Max: 3
* @Default: 2 * @Default: 2
* *
* This ini is used to set suspend mode. Configurations are as follows: * This ini is used to set suspend mode. Configurations are as follows:
* 0 - Does not support suspend. * 0 - Does not support suspend.
* 1 - Legency suspend mode, PDEV suspend. * 1 - Legency suspend mode, PDEV suspend.
* 2 - WOW suspend mode. * 2 - WOW suspend mode.
* 3 - Full power down while suspend.
* *
* Related: None * Related: None
* *
@@ -357,7 +358,7 @@
* </ini> * </ini>
*/ */
#define CFG_PMO_SUSPEND_MODE CFG_INI_UINT("gSuspendMode", \ #define CFG_PMO_SUSPEND_MODE CFG_INI_UINT("gSuspendMode", \
0, 2, 2, \ 0, 3, 2, \
CFG_VALUE_OR_DEFAULT, \ CFG_VALUE_OR_DEFAULT, \
"Suspend mode") "Suspend mode")

View File

@@ -175,11 +175,13 @@ enum powersave_mode {
* @PMO_SUSPEND_NONE: Does not support suspend * @PMO_SUSPEND_NONE: Does not support suspend
* @PMO_SUSPEND_LEGENCY: Legency PDEV suspend mode * @PMO_SUSPEND_LEGENCY: Legency PDEV suspend mode
* @PMO_SUSPEND_WOW: WoW suspend mode * @PMO_SUSPEND_WOW: WoW suspend mode
* @PMO_FULL_POWER_DOWN: Full power down while suspend
*/ */
enum pmo_suspend_mode { enum pmo_suspend_mode {
PMO_SUSPEND_NONE = 0, PMO_SUSPEND_NONE = 0,
PMO_SUSPEND_LEGENCY, PMO_SUSPEND_LEGENCY,
PMO_SUSPEND_WOW PMO_SUSPEND_WOW,
PMO_FULL_POWER_DOWN
}; };
#define PMO_TARGET_SUSPEND_TIMEOUT (4000) #define PMO_TARGET_SUSPEND_TIMEOUT (4000)

View File

@@ -5130,4 +5130,21 @@ static inline void hdd_dp_ssr_unprotect(void)
{ {
qdf_atomic_dec(&dp_protect_entry_count); qdf_atomic_dec(&dp_protect_entry_count);
} }
#ifdef FEATURE_WLAN_FULL_POWER_DOWN_SUPPORT
/**
* hdd_set_suspend_mode: set the suspend_mode state to pld based on the
* configuration option from INI file
* @hdd_ctx: HDD context
*
* Return: 0 for success
* Non zero failure code for errors
*/
int hdd_set_suspend_mode(struct hdd_context *hdd_ctx);
#else
static inline int hdd_set_suspend_mode(struct hdd_context *hdd_ctx)
{
return 0;
}
#endif
#endif /* end #if !defined(WLAN_HDD_MAIN_H) */ #endif /* end #if !defined(WLAN_HDD_MAIN_H) */

View File

@@ -621,6 +621,25 @@ static inline int wlan_hdd_rx_thread_suspend(struct hdd_context *hdd_ctx)
} }
#endif #endif
#ifdef FEATURE_WLAN_FULL_POWER_DOWN_SUPPORT
/**
* wlan_hdd_is_full_power_down_enable()- Check wlan full power down
* @hdd_ctx: HDD context
*
* check whether the wlan full power down is enabled or not.
*
* Return: true if wlan full power enabled else false
*/
bool
wlan_hdd_is_full_power_down_enable(struct hdd_context *hdd_ctx);
#else
static inline bool
wlan_hdd_is_full_power_down_enable(struct hdd_context *hdd_ctx)
{
return false;
}
#endif
#ifdef FEATURE_ANI_LEVEL_REQUEST #ifdef FEATURE_ANI_LEVEL_REQUEST
/** /**
* wlan_hdd_get_ani_level() - Wrapper to call API to fetch ani level * wlan_hdd_get_ani_level() - Wrapper to call API to fetch ani level

View File

@@ -638,6 +638,10 @@ static int __hdd_soc_probe(struct device *dev,
hdd_start_complete(0); hdd_start_complete(0);
hdd_thermal_mitigation_register(hdd_ctx, dev); hdd_thermal_mitigation_register(hdd_ctx, dev);
errno = hdd_set_suspend_mode(hdd_ctx);
if (errno)
hdd_err("Failed to set suspend mode in PLD; errno:%d", errno);
hdd_soc_load_unlock(dev); hdd_soc_load_unlock(dev);
return 0; return 0;
@@ -970,14 +974,17 @@ static void __hdd_soc_recovery_shutdown(void)
struct hdd_context *hdd_ctx; struct hdd_context *hdd_ctx;
void *hif_ctx; void *hif_ctx;
/* recovery starts via firmware down indication; ensure we got one */
QDF_BUG(cds_is_driver_recovering());
hdd_init_start_completion();
hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
if (!hdd_ctx) if (!hdd_ctx)
return; return;
if (wlan_hdd_is_full_power_down_enable(hdd_ctx))
cds_set_driver_state(CDS_DRIVER_STATE_RECOVERING);
/* recovery starts via firmware down indication; ensure we got one */
QDF_BUG(cds_is_driver_recovering());
hdd_init_start_completion();
/* /*
* Perform SSR related cleanup if it has not already been done as a * Perform SSR related cleanup if it has not already been done as a
* part of receiving the uevent. * part of receiving the uevent.

View File

@@ -17531,6 +17531,20 @@ static int hdd_register_driver_retry(void)
return errno; return errno;
} }
#ifdef FEATURE_WLAN_FULL_POWER_DOWN_SUPPORT
int hdd_set_suspend_mode(struct hdd_context *hdd_ctx)
{
int errno;
if (wlan_hdd_is_full_power_down_enable(hdd_ctx))
errno = pld_set_suspend_mode(PLD_FULL_POWER_DOWN);
else
errno = pld_set_suspend_mode(PLD_SUSPEND);
return errno;
}
#endif
int hdd_driver_load(void) int hdd_driver_load(void)
{ {
struct osif_driver_sync *driver_sync; struct osif_driver_sync *driver_sync;

View File

@@ -2258,6 +2258,18 @@ hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
} }
#endif #endif
#ifdef FEATURE_WLAN_FULL_POWER_DOWN_SUPPORT
bool wlan_hdd_is_full_power_down_enable(struct hdd_context *hdd_ctx)
{
if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) == PMO_FULL_POWER_DOWN) {
hdd_info_rl("Wlan full power down is enabled while suspend");
return true;
}
return false;
}
#endif
/** /**
* __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
* @wiphy: Pointer to wiphy * @wiphy: Pointer to wiphy
@@ -2296,6 +2308,12 @@ static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
return -EINVAL; return -EINVAL;
} }
if (wlan_hdd_is_full_power_down_enable(hdd_ctx)) {
hdd_debug("Driver has been re-initialized; Skipping resume");
exit_code = 0;
goto exit_with_code;
}
if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
hdd_debug("Driver is not enabled; Skipping resume"); hdd_debug("Driver is not enabled; Skipping resume");
exit_code = 0; exit_code = 0;
@@ -2472,6 +2490,11 @@ static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
return -EINVAL; return -EINVAL;
} }
if (wlan_hdd_is_full_power_down_enable(hdd_ctx)) {
hdd_debug("Driver will be shutdown; Skipping suspend");
return 0;
}
if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
hdd_debug("Driver Modules not Enabled "); hdd_debug("Driver Modules not Enabled ");
return 0; return 0;

View File

@@ -321,6 +321,16 @@ enum pld_driver_mode {
PLD_FTM_COLDBOOT_CALIBRATION = 10 PLD_FTM_COLDBOOT_CALIBRATION = 10
}; };
/**
* enum pld_suspend_mode - WLAN suspend mode
* @PLD_SUSPEND: suspend
* @PLD_FULL_POWER_DOWN: full power down while suspend
*/
enum pld_suspend_mode {
PLD_SUSPEND,
PLD_FULL_POWER_DOWN,
};
/** /**
* struct pld_device_version - WLAN device version info * struct pld_device_version - WLAN device version info
* @family_number: family number of WLAN SOC HW * @family_number: family number of WLAN SOC HW
@@ -490,6 +500,33 @@ void pld_deinit(void);
*/ */
int pld_set_mode(u8 mode); int pld_set_mode(u8 mode);
#ifdef FEATURE_WLAN_FULL_POWER_DOWN_SUPPORT
/**
* pld_set_suspend_mode() - set suspend mode in PLD module
* @mode: pld suspend mode
*
* Return: 0 for success
* Non zero failure code for errors
*/
int pld_set_suspend_mode(enum pld_suspend_mode mode);
/**
* pld_is_full_power_down_enable() - check full power down is enabled or not
*
* Return: true if full power down is enabled else false
*/
bool pld_is_full_power_down_enable(void);
#else
static inline int pld_set_suspend_mode(enum pld_suspend_mode mode)
{
return 0;
}
static inline bool pld_is_full_power_down_enable(void)
{
return false;
}
#endif
int pld_register_driver(struct pld_driver_ops *ops); int pld_register_driver(struct pld_driver_ops *ops);
void pld_unregister_driver(void); void pld_unregister_driver(void);

View File

@@ -130,6 +130,39 @@ int pld_set_mode(u8 mode)
return 0; return 0;
} }
#ifdef FEATURE_WLAN_FULL_POWER_DOWN_SUPPORT
int pld_set_suspend_mode(enum pld_suspend_mode mode)
{
struct pld_context *pld_context;
int ret;
pld_context = pld_get_global_context();
if (!pld_context)
return -ENOMEM;
pld_context->suspend_mode = mode;
ret = pld_pcie_set_suspend_mode(mode);
return ret;
}
bool pld_is_full_power_down_enable(void)
{
struct pld_context *pld_context;
pld_context = pld_get_global_context();
if (!pld_context)
goto out;
if (pld_context->suspend_mode == PLD_FULL_POWER_DOWN)
return true;
out:
return false;
}
#endif
/** /**
* pld_get_global_context() - Get global context of PLD * pld_get_global_context() - Get global context of PLD
* *

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for * Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the * any purpose with or without fee is hereby granted, provided that the
@@ -34,6 +34,7 @@ struct pld_context {
struct list_head dev_list; struct list_head dev_list;
uint32_t pld_driver_state; uint32_t pld_driver_state;
uint8_t mode; uint8_t mode;
enum pld_suspend_mode suspend_mode;
}; };
struct pld_context *pld_get_global_context(void); struct pld_context *pld_get_global_context(void);

View File

@@ -659,6 +659,35 @@ struct cnss_wlan_runtime_ops runtime_pm_ops = {
}; };
#endif #endif
#ifdef FEATURE_WLAN_FULL_POWER_DOWN_SUPPORT
static enum cnss_suspend_mode pld_pcie_suspend_mode = CNSS_SUSPEND_LEGACY;
int pld_pcie_set_suspend_mode(enum pld_suspend_mode mode)
{
struct pld_context *pld_ctx = pld_get_global_context();
enum cnss_suspend_mode suspend_mode;
if (!pld_ctx)
return -ENOMEM;
switch (pld_ctx->suspend_mode) {
case PLD_SUSPEND:
suspend_mode = CNSS_SUSPEND_LEGACY;
break;
case PLD_FULL_POWER_DOWN:
suspend_mode = CNSS_SUSPEND_POWER_DOWN;
break;
default:
suspend_mode = CNSS_SUSPEND_LEGACY;
break;
}
pld_pcie_suspend_mode = suspend_mode;
return 0;
}
#endif
struct cnss_wlan_driver pld_pcie_ops = { struct cnss_wlan_driver pld_pcie_ops = {
.name = PLD_PCIE_OPS_NAME, .name = PLD_PCIE_OPS_NAME,
.id_table = pld_pcie_id_table, .id_table = pld_pcie_id_table,
@@ -686,6 +715,9 @@ struct cnss_wlan_driver pld_pcie_ops = {
#ifdef FEATURE_GET_DRIVER_MODE #ifdef FEATURE_GET_DRIVER_MODE
.get_driver_mode = pld_pcie_get_mode, .get_driver_mode = pld_pcie_get_mode,
#endif #endif
#ifdef FEATURE_WLAN_FULL_POWER_DOWN_SUPPORT
.suspend_mode = &pld_pcie_suspend_mode,
#endif
}; };
/** /**

View File

@@ -137,6 +137,23 @@ static inline int pld_pcie_wlan_pm_control(struct device *dev, bool vote)
} }
#endif #endif
#ifdef FEATURE_WLAN_FULL_POWER_DOWN_SUPPORT
/**
* pld_pcie_set_suspend_mode() - Set current WLAN suspend mode
*
* This function is to set current wlan suspend mode for CNSS2
*
* Return: 0 for success
* Non zero failure code for errors
*/
int pld_pcie_set_suspend_mode(enum pld_suspend_mode mode);
#else
static inline int pld_pcie_set_suspend_mode(enum pld_suspend_mode mode)
{
return 0;
}
#endif
#ifndef CONFIG_PLD_PCIE_CNSS #ifndef CONFIG_PLD_PCIE_CNSS
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
static inline void *pld_pcie_smmu_get_domain(struct device *dev) static inline void *pld_pcie_smmu_get_domain(struct device *dev)