Browse Source

qcacld-3.0: Shutdown WLAN in system suspend prepare

This re-introduces the orignal patch which shutdowns WLAN in system
suspend prepare.

Orignal patch Id1f5172a7fc1792c83c8c1c20127de815f7e4980 is reverted by
Ic82db9dc0ca9d6686df99926335af27abc61cdb5 for deadlock issue.

However, deadlock between cnss_pm_notify and unregister_pm_notifier is
not caused by Id1f5172a7fc1792c83c8c1c20127de815f7e4980. So restore it
and add flag to enable/disable feature shutdown wlan in system suspend.

Deadlock issue is caused by "up_write(&cnss_pm_sem) is invoked before
down_write(&cnss_pm_sem) in function cnss_pm_notify". The issue can be
fixed by changes I533c373b85f554fbcceb562d9f56c6b88e5155bb and
I7768fdbeb1fa8cd6ef3b260eb0aafb231aeed324.

Change-Id: I25e4398a8d3b1a52cf7bc554af74d123ec797c6e
CRs-Fixed: 3287742
Yu Ouyang 2 years ago
parent
commit
85f34a3bb9

+ 2 - 0
Kbuild

@@ -4573,6 +4573,8 @@ endif
 
 cppflags-$(CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET) += -DWLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET
 
+ccflags-$(CONFIG_SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND) += -DSHUTDOWN_WLAN_IN_SYSTEM_SUSPEND
+
 ifeq ($(CONFIG_WLAN_FEATURE_MCC_QUOTA), y)
 cppflags-y += -DWLAN_FEATURE_MCC_QUOTA
 ifdef CONFIG_WLAN_MCC_MIN_CHANNEL_QUOTA

+ 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 - 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")
 

+ 1 - 1
components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h

@@ -175,7 +175,7 @@ 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 while suspend mode
+ * @PMO_SUSPEND_SHUTDOWN: Shutdown suspend mode. Shutdown while suspend
  */
 enum pmo_suspend_mode {
 	PMO_SUSPEND_NONE = 0,

+ 2 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1710,6 +1710,7 @@ enum wlan_state_ctrl_str_id {
  * @dump_in_progress: Stores value of dump in progress
  * @hdd_dual_sta_policy: Concurrent STA policy configuration
  * @is_wlan_disabled: if wlan is disabled by userspace
+ * @pm_notifier: PM notifier of hdd modules
  */
 struct hdd_context {
 	struct wlan_objmgr_psoc *psoc;
@@ -1889,6 +1890,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;
 	struct acs_dfs_policy acs_policy;
 	uint16_t wmi_max_len;
 	struct suspend_resume_stats suspend_resume_stats;

+ 77 - 0
core/hdd/src/wlan_hdd_main.c

@@ -83,6 +83,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"
@@ -9395,6 +9396,79 @@ out:
 	return ret;
 }
 
+#ifdef SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND
+static QDF_STATUS
+hdd_shutdown_wlan_in_suspend_prepare(struct hdd_context *hdd_ctx)
+{
+#define SHUTDOWN_IN_SUSPEND_RETRY 10
+
+	int count = 0;
+
+	if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) != PMO_SUSPEND_SHUTDOWN) {
+		hdd_debug("shutdown in suspend not supported");
+		return 0;
+	}
+
+	while (hdd_is_any_interface_open(hdd_ctx) &&
+	       count < SHUTDOWN_IN_SUSPEND_RETRY) {
+		count++;
+		hdd_debug_rl("sleep 50ms to wait adapters stopped, #%d", count);
+		msleep(50);
+	}
+	if (count >= SHUTDOWN_IN_SUSPEND_RETRY) {
+		hdd_err("some adapters not stopped");
+		return -EBUSY;
+	}
+
+	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)
+{
+	struct hdd_context *hdd_ctx = container_of(b, struct hdd_context,
+						   pm_notifier);
+
+	if (wlan_hdd_validate_context(hdd_ctx) != 0)
+		return NOTIFY_STOP;
+
+	hdd_debug("got PM event: %lu", event);
+
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+	case PM_HIBERNATION_PREPARE:
+		if (0 != hdd_shutdown_wlan_in_suspend_prepare(hdd_ctx))
+			return NOTIFY_STOP;
+		break;
+	case PM_POST_SUSPEND:
+	case PM_POST_HIBERNATION:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static void hdd_pm_notifier_init(struct hdd_context *hdd_ctx)
+{
+	hdd_ctx->pm_notifier.notifier_call = hdd_pm_notify;
+	register_pm_notifier(&hdd_ctx->pm_notifier);
+}
+
+static void hdd_pm_notifier_deinit(struct hdd_context *hdd_ctx)
+{
+	unregister_pm_notifier(&hdd_ctx->pm_notifier);
+}
+#else
+static inline void hdd_pm_notifier_init(struct hdd_context *hdd_ctx)
+{
+}
+
+static inline void hdd_pm_notifier_deinit(struct hdd_context *hdd_ctx)
+{
+}
+#endif
+
 /**
  * hdd_context_deinit() - Deinitialize HDD context
  * @hdd_ctx:    HDD context.
@@ -9438,6 +9512,7 @@ void hdd_context_destroy(struct hdd_context *hdd_ctx)
 	hdd_ctx->config = NULL;
 	cfg_release();
 
+	hdd_pm_notifier_deinit(hdd_ctx);
 	qdf_delayed_work_destroy(&hdd_ctx->psoc_idle_timeout_work);
 	wiphy_free(hdd_ctx->wiphy);
 }
@@ -12631,6 +12706,8 @@ struct hdd_context *hdd_context_create(struct device *dev)
 		goto wiphy_dealloc;
 	}
 
+	hdd_pm_notifier_init(hdd_ctx);
+
 	hdd_ctx->parent_dev = dev;
 	hdd_ctx->last_scan_reject_vdev_id = WLAN_UMAC_VDEV_ID_MAX;