Procházet zdrojové kódy

qcacmn: Add support to acquire wake lock during user scan

Acquire wakelock to handle the case where APP's send
scan to connect. If suspend is received during scan, scan will be
aborted and APP will not get scan result and will not connect.
eg if PNO is implemented in framework.

Fix is to avoid the system suspend by taking the wake-lock
during scan. Added INI wake_lock_in_user_scan to control this.
The INI is disabled by default.

Change-Id: I62fdbbcbc6f049cb4e36e774d5a417600a2dfa86
CRs-Fixed: 2381622
Abhishek Singh před 6 roky
rodič
revize
0c1dedb899

+ 5 - 1
os_if/linux/scan/inc/wlan_cfg80211_scan.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 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
@@ -45,6 +45,8 @@
 #define QCOM_VENDOR_IE_AGE_TYPE  0x100
 #define QCOM_VENDOR_IE_AGE_LEN   (sizeof(qcom_ie_age) - 2)
 #define SCAN_DONE_EVENT_BUF_SIZE 4096
+#define SCAN_WAKE_LOCK_CONNECT_DURATION (1 * 1000) /* in msec */
+#define SCAN_WAKE_LOCK_SCAN_DURATION (5 * 1000) /* in msec */
 
 /**
  * typedef struct qcom_ie_age - age ie
@@ -79,12 +81,14 @@ typedef struct {
  * scan_req_q_lock: Protect scan request queue
  * req_id: Scan request Id
  * runtime_pm_lock: Runtime suspend lock
+ * scan_wake_lock: Scan wake lock
  */
 struct osif_scan_pdev{
 	qdf_list_t scan_req_q;
 	qdf_mutex_t scan_req_q_lock;
 	wlan_scan_requester req_id;
 	qdf_runtime_lock_t runtime_pm_lock;
+	qdf_wake_lock_t scan_wake_lock;
 };
 
 /*

+ 92 - 6
os_if/linux/scan/src/wlan_cfg80211_scan.c

@@ -38,6 +38,9 @@
 #include <wlan_policy_mgr_api.h>
 #endif
 #include <wlan_reg_services_api.h>
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+#include "host_diag_core_event.h"
+#endif
 
 static const
 struct nla_policy scan_policy[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1] = {
@@ -864,6 +867,58 @@ nla_put_failure:
 	qdf_mem_free(req);
 }
 
+/**
+ * wlan_scan_acquire_wake_lock_timeout() - acquire scan wake lock
+ * @psoc: psoc ptr
+ * @scan_wake_lock: Scan wake lock
+ * @timeout: timeout in ms
+ *
+ * Return: void
+ */
+static inline
+void wlan_scan_acquire_wake_lock_timeout(struct wlan_objmgr_psoc *psoc,
+					 qdf_wake_lock_t *scan_wake_lock,
+					 uint32_t timeout)
+{
+	if (!psoc || !scan_wake_lock)
+		return;
+
+	if (ucfg_scan_wake_lock_in_user_scan(psoc))
+		qdf_wake_lock_timeout_acquire(scan_wake_lock, timeout);
+}
+
+
+/**
+ * wlan_scan_release_wake_lock() - release scan wake lock
+ * @psoc: psoc ptr
+ * @scan_wake_lock: Scan wake lock
+ *
+ * Return: void
+ */
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+static inline
+void wlan_scan_release_wake_lock(struct wlan_objmgr_psoc *psoc,
+				 qdf_wake_lock_t *scan_wake_lock)
+{
+	if (!psoc || !scan_wake_lock)
+		return;
+
+	if (ucfg_scan_wake_lock_in_user_scan(psoc))
+		qdf_wake_lock_release(scan_wake_lock,
+				      WIFI_POWER_EVENT_WAKELOCK_SCAN);
+}
+#else
+static inline
+void wlan_scan_release_wake_lock(struct wlan_objmgr_psoc *psoc,
+				 qdf_wake_lock_t *scan_wake_lock)
+{
+	if (!psoc || !scan_wake_lock)
+		return;
+
+	if (ucfg_scan_wake_lock_in_user_scan(psoc))
+		qdf_wake_lock_release(scan_wake_lock, 0);
+}
+#endif
 
 /**
  * wlan_cfg80211_scan_done_callback() - scan done callback function called after
@@ -937,10 +992,26 @@ static void wlan_cfg80211_scan_done_callback(
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
 allow_suspend:
 	osif_priv = wlan_pdev_get_ospriv(pdev);
-	if (qdf_list_empty(&osif_priv->osif_scan->scan_req_q))
+	if (qdf_list_empty(&osif_priv->osif_scan->scan_req_q)) {
+		struct wlan_objmgr_psoc *psoc;
+
 		qdf_runtime_pm_allow_suspend(
 			&osif_priv->osif_scan->runtime_pm_lock);
 
+		psoc = wlan_pdev_get_psoc(pdev);
+		wlan_scan_release_wake_lock(psoc,
+					&osif_priv->osif_scan->scan_wake_lock);
+		/*
+		 * Acquire wakelock to handle the case where APP's tries
+		 * to suspend immediately after the driver gets connect
+		 * request(i.e after scan) from supplicant, this result in
+		 * app's is suspending and not able to process the connect
+		 * request to AP
+		 */
+		wlan_scan_acquire_wake_lock_timeout(psoc,
+					&osif_priv->osif_scan->scan_wake_lock,
+					SCAN_WAKE_LOCK_CONNECT_DURATION);
+	}
 }
 
 QDF_STATUS wlan_scan_runtime_pm_init(struct wlan_objmgr_pdev *pdev)
@@ -990,9 +1061,10 @@ QDF_STATUS wlan_cfg80211_scan_priv_init(struct wlan_objmgr_pdev *pdev)
 	}
 	/* Initialize the scan request queue */
 	osif_priv->osif_scan = scan_priv;
+	scan_priv->req_id = req_id;
 	qdf_list_create(&scan_priv->scan_req_q, WLAN_MAX_SCAN_COUNT);
 	qdf_mutex_create(&scan_priv->scan_req_q_lock);
-	scan_priv->req_id = req_id;
+	qdf_wake_lock_create(&scan_priv->scan_wake_lock, "scan_wake_lock");
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -1008,11 +1080,12 @@ QDF_STATUS wlan_cfg80211_scan_priv_deinit(struct wlan_objmgr_pdev *pdev)
 
 	wlan_cfg80211_cleanup_scan_queue(pdev, NULL);
 	scan_priv = osif_priv->osif_scan;
-	ucfg_scan_unregister_requester(psoc, scan_priv->req_id);
-	qdf_list_destroy(&scan_priv->scan_req_q);
+	qdf_wake_lock_destroy(&scan_priv->scan_wake_lock);
 	qdf_mutex_destroy(&scan_priv->scan_req_q_lock);
-	qdf_mem_free(scan_priv);
+	qdf_list_destroy(&scan_priv->scan_req_q);
+	ucfg_scan_unregister_requester(psoc, scan_priv->req_id);
 	osif_priv->osif_scan = NULL;
+	qdf_mem_free(scan_priv);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -1385,6 +1458,16 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
 	wlan_scan_request_enqueue(pdev, request, params->source,
 				  req->scan_req.scan_id);
 
+	/*
+	 * Acquire wakelock to handle the case where APP's send scan to connect.
+	 * If suspend is received during scan scan will be aborted and APP will
+	 * not get scan result and not connect. eg if PNO is implemented in
+	 * framework.
+	 */
+	wlan_scan_acquire_wake_lock_timeout(psoc,
+					&osif_priv->osif_scan->scan_wake_lock,
+					SCAN_WAKE_LOCK_SCAN_DURATION);
+
 	qdf_runtime_pm_prevent_suspend(
 		&osif_priv->osif_scan->runtime_pm_lock);
 
@@ -1395,9 +1478,12 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
 			cfg80211_err("HO is in progress.So defer the scan by informing busy");
 		wlan_scan_request_dequeue(pdev, scan_id, &request,
 					  &params->source, &netdev);
-		if (qdf_list_empty(&osif_priv->osif_scan->scan_req_q))
+		if (qdf_list_empty(&osif_priv->osif_scan->scan_req_q)) {
 			qdf_runtime_pm_allow_suspend(
 				&osif_priv->osif_scan->runtime_pm_lock);
+			wlan_scan_release_wake_lock(psoc,
+				&osif_priv->osif_scan->scan_wake_lock);
+		}
 	}
 	ret = qdf_status_to_os_return(qdf_status);
 

+ 2 - 0
umac/scan/core/src/wlan_scan_main.h

@@ -279,6 +279,7 @@ struct extscan_def_config {
  * @active_dwell: default active dwell time
  * @allow_dfs_chan_in_first_scan: first scan should contain dfs channels or not.
  * @allow_dfs_chan_in_scan: Scan DFS channels or not.
+ * @use_wake_lock_in_user_scan: if wake lock will be acquired during user scan
  * @active_dwell_2g: default active dwell time for 2G channels, if it's not zero
  * @passive_dwell:default passive dwell time
  * @max_rest_time: default max rest time
@@ -356,6 +357,7 @@ struct scan_default_params {
 	uint32_t active_dwell;
 	bool allow_dfs_chan_in_first_scan;
 	bool allow_dfs_chan_in_scan;
+	bool use_wake_lock_in_user_scan;
 	uint32_t active_dwell_2g;
 	uint32_t passive_dwell;
 	uint32_t max_rest_time;

+ 21 - 0
umac/scan/dispatcher/inc/wlan_scan_cfg.h

@@ -434,6 +434,26 @@
 				CFG_VALUE_OR_DEFAULT, \
 				"minimum time spent on home channel")
 
+/*
+ * <ini>
+ * wake_lock_in_user_scan - use wake lock during user scan
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to define if wake lock is held used during user scan req
+ *
+ * Related: Scan
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_ENABLE_WAKE_LOCK_IN_SCAN CFG_INI_BOOL( \
+				"wake_lock_in_user_scan", \
+				false, \
+				"use wake lock during scan")
+
 /*
  * <ini>
  * gIdleTimeConc - Data inactivity time in msec.
@@ -464,6 +484,7 @@
 
 #define CFG_SCAN_ALL \
 	CFG(CFG_DROP_BCN_ON_CHANNEL_MISMATCH) \
+	CFG(CFG_ENABLE_WAKE_LOCK_IN_SCAN) \
 	CFG(CFG_ACTIVE_MAX_CHANNEL_TIME) \
 	CFG(CFG_ENABLE_DFS_SCAN) \
 	CFG(CFG_INITIAL_NO_DFS_SCAN) \

+ 9 - 0
umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h

@@ -778,6 +778,15 @@ void ucfg_scan_cfg_set_dfs_chan_scan_allowed(struct wlan_objmgr_psoc *psoc,
 	return wlan_scan_cfg_set_dfs_chan_scan_allowed(psoc, dfs_scan_enable);
 }
 
+/**
+ * ucfg_scan_wake_lock_in_user_scan() - API to determine if wake lock in user
+ * scan is used.
+ * @psoc: pointer to psoc object
+ *
+ * Return: true if wake lock in user scan is required
+ */
+bool ucfg_scan_wake_lock_in_user_scan(struct wlan_objmgr_psoc *psoc);
+
 /**
  * ucfg_scan_cfg_get_conc_max_resttime() - API to get max rest time
  * @psoc: pointer to psoc object

+ 13 - 0
umac/scan/dispatcher/src/wlan_scan_ucfg_api.c

@@ -1475,6 +1475,8 @@ wlan_scan_global_init(struct wlan_objmgr_psoc *psoc,
 				!cfg_get(psoc, CFG_INITIAL_NO_DFS_SCAN);
 	scan_obj->scan_def.allow_dfs_chan_in_scan =
 				cfg_get(psoc, CFG_ENABLE_DFS_SCAN);
+	scan_obj->scan_def.use_wake_lock_in_user_scan =
+				cfg_get(psoc, CFG_ENABLE_WAKE_LOCK_IN_SCAN);
 	scan_obj->scan_def.active_dwell_2g =
 			 cfg_get(psoc, CFG_ACTIVE_MAX_2G_CHANNEL_TIME);
 	scan_obj->scan_def.passive_dwell =
@@ -2319,6 +2321,17 @@ bool ucfg_scan_get_bt_activity(struct wlan_objmgr_psoc *psoc)
 	return scan_obj->bt_a2dp_enabled;
 }
 
+bool ucfg_scan_wake_lock_in_user_scan(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_scan_obj *scan_obj;
+
+	scan_obj = wlan_psoc_get_scan_obj(psoc);
+	if (!scan_obj)
+		return false;
+
+	return scan_obj->scan_def.use_wake_lock_in_user_scan;
+}
+
 QDF_STATUS
 ucfg_scan_set_global_config(struct wlan_objmgr_psoc *psoc,
 			       enum scan_config config, uint32_t val)