diff --git a/Kbuild b/Kbuild index 2f3bd323cd..23de2fb2c4 100644 --- a/Kbuild +++ b/Kbuild @@ -4169,6 +4169,10 @@ endif 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_GET_DRIVER_MODE) += -DFEATURE_GET_DRIVER_MODE diff --git a/components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h b/components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h index 61c396702b..bdbc6570b2 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 - Full power down 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 512cf406d8..b07785389f 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_FULL_POWER_DOWN: Full power down while suspend */ enum pmo_suspend_mode { PMO_SUSPEND_NONE = 0, PMO_SUSPEND_LEGENCY, - PMO_SUSPEND_WOW + PMO_SUSPEND_WOW, + PMO_FULL_POWER_DOWN }; #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 80851899a4..3aa20b4c33 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -5130,4 +5130,21 @@ static inline void hdd_dp_ssr_unprotect(void) { 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) */ diff --git a/core/hdd/inc/wlan_hdd_power.h b/core/hdd/inc/wlan_hdd_power.h index 5b663a636a..0963d2b8b2 100644 --- a/core/hdd/inc/wlan_hdd_power.h +++ b/core/hdd/inc/wlan_hdd_power.h @@ -621,6 +621,25 @@ static inline int wlan_hdd_rx_thread_suspend(struct hdd_context *hdd_ctx) } #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 /** * wlan_hdd_get_ani_level() - Wrapper to call API to fetch ani level diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index ac6b27065a..0c62ae07a3 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -638,6 +638,10 @@ static int __hdd_soc_probe(struct device *dev, hdd_start_complete(0); 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); return 0; @@ -970,14 +974,17 @@ static void __hdd_soc_recovery_shutdown(void) struct hdd_context *hdd_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); if (!hdd_ctx) 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 * part of receiving the uevent. diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 8ba3c12ce3..0fb8b9ba4c 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -17531,6 +17531,20 @@ static int hdd_register_driver_retry(void) 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) { struct osif_driver_sync *driver_sync; diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 83eeda3da7..2680e579c0 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -2258,6 +2258,18 @@ hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid) } #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 * @wiphy: Pointer to wiphy @@ -2296,6 +2308,12 @@ static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) 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) { hdd_debug("Driver is not enabled; Skipping resume"); exit_code = 0; @@ -2472,6 +2490,11 @@ static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, 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) { hdd_debug("Driver Modules not Enabled "); return 0; diff --git a/core/pld/inc/pld_common.h b/core/pld/inc/pld_common.h index 141e0bd29f..99c77eb40c 100644 --- a/core/pld/inc/pld_common.h +++ b/core/pld/inc/pld_common.h @@ -321,6 +321,16 @@ enum pld_driver_mode { 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 * @family_number: family number of WLAN SOC HW @@ -490,6 +500,33 @@ void pld_deinit(void); */ 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); void pld_unregister_driver(void); diff --git a/core/pld/src/pld_common.c b/core/pld/src/pld_common.c index 8bb7833a8b..6493b1952c 100644 --- a/core/pld/src/pld_common.c +++ b/core/pld/src/pld_common.c @@ -130,6 +130,39 @@ int pld_set_mode(u8 mode) 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 * diff --git a/core/pld/src/pld_internal.h b/core/pld/src/pld_internal.h index 0974197c23..b556ba6086 100644 --- a/core/pld/src/pld_internal.h +++ b/core/pld/src/pld_internal.h @@ -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 * any purpose with or without fee is hereby granted, provided that the @@ -34,6 +34,7 @@ struct pld_context { struct list_head dev_list; uint32_t pld_driver_state; uint8_t mode; + enum pld_suspend_mode suspend_mode; }; struct pld_context *pld_get_global_context(void); diff --git a/core/pld/src/pld_pcie.c b/core/pld/src/pld_pcie.c index 0f8d308bf0..02d6dd2ab1 100644 --- a/core/pld/src/pld_pcie.c +++ b/core/pld/src/pld_pcie.c @@ -659,6 +659,35 @@ struct cnss_wlan_runtime_ops runtime_pm_ops = { }; #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 = { .name = PLD_PCIE_OPS_NAME, .id_table = pld_pcie_id_table, @@ -686,6 +715,9 @@ struct cnss_wlan_driver pld_pcie_ops = { #ifdef FEATURE_GET_DRIVER_MODE .get_driver_mode = pld_pcie_get_mode, #endif +#ifdef FEATURE_WLAN_FULL_POWER_DOWN_SUPPORT + .suspend_mode = &pld_pcie_suspend_mode, +#endif }; /** diff --git a/core/pld/src/pld_pcie.h b/core/pld/src/pld_pcie.h index 9dd6c69578..4cade9a07d 100644 --- a/core/pld/src/pld_pcie.h +++ b/core/pld/src/pld_pcie.h @@ -137,6 +137,23 @@ static inline int pld_pcie_wlan_pm_control(struct device *dev, bool vote) } #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 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) static inline void *pld_pcie_smmu_get_domain(struct device *dev)