Browse Source

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
Ke Huang 3 years ago
parent
commit
b43015863f

+ 4 - 0
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
 

+ 3 - 2
components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h

@@ -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 - Full power down 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")
 

+ 3 - 1
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)

+ 17 - 0
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) */

+ 19 - 0
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

+ 11 - 4
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.

+ 14 - 0
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;

+ 23 - 0
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;

+ 37 - 0
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);
 

+ 33 - 0
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
  *

+ 2 - 1
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);

+ 32 - 0
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
 };
 
 /**

+ 17 - 0
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)