Pārlūkot izejas kodu

qcacld-3.0: Idle shutdown in suspend

To support shutdown WLAN when system goes into suspend, add idle shutdown
in cfg80211 suspend function.

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 state.

Idle shutdown must be processed in system active, so schedule delayed
work to execute it. After calling schedule, retrun EAGAIN directly to PM.

Change-Id: I08818517d05e7866d50e3f92cfdc9fa1a4d0e63f
CRs-Fixed: 3081480
Yu Ouyang 3 gadi atpakaļ
vecāks
revīzija
675b9de61a

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

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -175,13 +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
+ * @PMO_SUSPEND_SHUTDOWN: Shutdown suspend mode. Shutdown while suspend
  */
 enum pmo_suspend_mode {
 	PMO_SUSPEND_NONE = 0,
 	PMO_SUSPEND_LEGENCY,
 	PMO_SUSPEND_WOW,
-	PMO_FULL_POWER_DOWN
+	PMO_SUSPEND_SHUTDOWN
 };
 
 #define PMO_TARGET_SUSPEND_TIMEOUT   (4000)

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

@@ -2021,6 +2021,9 @@ struct hdd_context {
 	/* Flag keeps track of wiphy suspend/resume */
 	bool is_wiphy_suspended;
 
+	/* Flag keeps track of idle shutdown triggered by suspend */
+	bool shutdown_in_suspend;
+
 #ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH
 	struct qdf_periodic_work bus_bw_work;
 	int cur_vote_level;
@@ -5249,4 +5252,12 @@ static inline int hdd_set_suspend_mode(struct hdd_context *hdd_ctx)
 	return 0;
 }
 #endif
+/*
+ * hdd_shutdown_wlan_in_suspend: shutdown wlan chip when suspend called
+ * @hdd_ctx: HDD context
+ *
+ * this function called by __wlan_hdd_cfg80211_suspend_wlan(), and it
+ * schedule idle shutdown work queue when no interface open.
+ */
+void hdd_shutdown_wlan_in_suspend(struct hdd_context *hdd_ctx);
 #endif /* end #if !defined(WLAN_HDD_MAIN_H) */

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

@@ -18029,6 +18029,23 @@ int hdd_set_suspend_mode(struct hdd_context *hdd_ctx)
 }
 #endif
 
+void hdd_shutdown_wlan_in_suspend(struct hdd_context *hdd_ctx)
+{
+/* schedule timeout cb as soon as possible */
+#define SHUTDOWN_IN_SUSPEND_WAIT_TIMEOUT 0
+/* prevent system suspend to let shutdown_restart work can be invoked */
+#define SHUTDOWN_IN_SUSPEND_PREVENT_TIMEOUT 5
+
+	if (!hdd_is_any_interface_open(hdd_ctx)) {
+		qdf_delayed_work_start(&hdd_ctx->psoc_idle_timeout_work,
+				       SHUTDOWN_IN_SUSPEND_WAIT_TIMEOUT);
+		hdd_prevent_suspend_timeout(SHUTDOWN_IN_SUSPEND_PREVENT_TIMEOUT,
+				WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_SHUTDOWN);
+	} else {
+		hdd_err("some adapter not stopped");
+	}
+}
+
 int hdd_driver_load(void)
 {
 	struct osif_driver_sync *driver_sync;

+ 15 - 6
core/hdd/src/wlan_hdd_power.c

@@ -2469,6 +2469,7 @@ static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
 	int rc;
 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_CFG80211_SUSPEND_WLAN;
 	struct hdd_hostapd_state *hapd_state;
+	enum pmo_suspend_mode suspend_mode;
 	struct csr_del_sta_params params = {
 		.peerMacAddr = QDF_MAC_ADDR_BCAST_INIT,
 		.reason_code = REASON_DEAUTH_NETWORK_LEAVING,
@@ -2492,14 +2493,20 @@ static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
 			return rc;
 	}
 
-	if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) == PMO_SUSPEND_NONE) {
+	suspend_mode = ucfg_pmo_get_suspend_mode(hdd_ctx->psoc);
+	if (suspend_mode == PMO_SUSPEND_NONE) {
 		hdd_info_rl("Suspend is not supported");
 		return -EINVAL;
 	}
 
-	if (wlan_hdd_is_full_power_down_enable(hdd_ctx)) {
-		hdd_debug("Driver will be shutdown; Skipping suspend");
-		return 0;
+	if (suspend_mode == PMO_SUSPEND_SHUTDOWN) {
+		hdd_info_rl("Shutdown WLAN in Suspend");
+		hdd_ctx->shutdown_in_suspend = true;
+		hdd_shutdown_wlan_in_suspend(hdd_ctx);
+		/* shutdown must be excute in active, so return -EAGAIN
+		 * to PM to exit and try again
+		 */
+		return -EAGAIN;
 	}
 
 	if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
@@ -2730,7 +2737,8 @@ static int _wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
 
 	/* If Wifi is off, return success for system suspend */
 	if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
-		hdd_debug("Driver Modules not Enabled ");
+		hdd_info("Driver Modules not Enabled");
+		hdd_ctx->shutdown_in_suspend = false;
 		return 0;
 	}
 
@@ -2779,7 +2787,8 @@ int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
 	 * the deadlock as idle shutdown waits for the dsc ops
 	 * to complete.
 	 */
-	hdd_psoc_idle_timer_stop(hdd_ctx);
+	if (!hdd_ctx->shutdown_in_suspend)
+		hdd_psoc_idle_timer_stop(hdd_ctx);
 
 	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
 	if (errno)