summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBapiraju Alla <balla@codeaurora.org>2020-06-26 15:29:47 +0530
committerchenpaul <chenpaul@google.com>2021-01-27 16:36:51 +0800
commitcea5ad8ce41ae161547e7f24cea319ab10c72ce6 (patch)
tree8048af93271df1ea2122c83bc40e66c92a956b1f
parente7d4167cb54953c8d5b144e29467593bf1d6d92f (diff)
downloadqca-wfi-host-cmn-cea5ad8ce41ae161547e7f24cea319ab10c72ce6.tar.gz
qcacmn: Enqueue scan request only after scan scheduling is success
Currently, vendor scan request is enqueued in the scan queue first and then posted into the scheduler queue. Now if there is an SSR in between, then scan request will be freed twice. Once in SSR context and again in the caller context because scan scheduling fails due to user disabled the scan. To resolve this, post the scan request in scheduler queue first. Once scan request scheduling is success, then enqueue the scan request in scan queue. This approach can lead to a race condition like after scheduling scan request, host may get scan response from firmware even before the scan request is queued. To avoid this race, scan request scheduling and enqueue should be protected by scan_req_q_lock. Change-Id: Ic26da0181fb9a902a8a4abb8f68d9fc668f1b3f2 CRs-Fixed: 2714495 Bug: 177955534 Signed-off-by: Srinivas Girigowda <quic_sgirigow@quicinc.com>
-rw-r--r--os_if/linux/scan/src/wlan_cfg80211_scan.c56
-rw-r--r--umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h8
-rw-r--r--umac/scan/dispatcher/src/wlan_scan_ucfg_api.c6
3 files changed, 46 insertions, 24 deletions
diff --git a/os_if/linux/scan/src/wlan_cfg80211_scan.c b/os_if/linux/scan/src/wlan_cfg80211_scan.c
index a14b80e07..c2ac41a08 100644
--- a/os_if/linux/scan/src/wlan_cfg80211_scan.c
+++ b/os_if/linux/scan/src/wlan_cfg80211_scan.c
@@ -663,20 +663,22 @@ wlan_copy_bssid_scan_request(struct scan_start_request *scan_req,
#endif
/**
- * wlan_scan_request_enqueue() - enqueue Scan Request
+ * wlan_schedule_scan_start_request() - Schedule scan start request
* @pdev: pointer to pdev object
* @req: Pointer to the scan request
* @source: source of the scan request
- * @scan_id: scan identifier
+ * @scan_start_req: pointer to scan start request
*
- * Enqueue scan request in the global scan list.This list
- * stores the active scan request information.
+ * Schedule scan start request and enqueue scan request in the global scan
+ * list. This list stores the active scan request information.
*
* Return: 0 on success, error number otherwise
*/
-static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev,
- struct cfg80211_scan_request *req,
- uint8_t source, uint32_t scan_id)
+static int
+wlan_schedule_scan_start_request(struct wlan_objmgr_pdev *pdev,
+ struct cfg80211_scan_request *req,
+ uint8_t source,
+ struct scan_start_request *scan_start_req)
{
struct scan_req *scan_req;
QDF_STATUS status;
@@ -686,6 +688,7 @@ static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev,
scan_req = qdf_mem_malloc(sizeof(*scan_req));
if (NULL == scan_req) {
cfg80211_alert("malloc failed for Scan req");
+ ucfg_scm_scan_free_scan_request_mem(scan_start_req);
return -ENOMEM;
}
@@ -694,12 +697,25 @@ static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev,
osif_scan = osif_ctx->osif_scan;
scan_req->scan_request = req;
scan_req->source = source;
- scan_req->scan_id = scan_id;
+ scan_req->scan_id = scan_start_req->scan_req.scan_id;
scan_req->dev = req->wdev->netdev;
qdf_mutex_acquire(&osif_scan->scan_req_q_lock);
- status = qdf_list_insert_back(&osif_scan->scan_req_q,
- &scan_req->node);
+ if (qdf_list_size(&osif_scan->scan_req_q) < WLAN_MAX_SCAN_COUNT) {
+ status = ucfg_scan_start(scan_start_req);
+ if (QDF_IS_STATUS_SUCCESS(status)) {
+ qdf_list_insert_back(&osif_scan->scan_req_q,
+ &scan_req->node);
+ } else {
+ cfg80211_err("scan req failed with error %d", status);
+ if (status == QDF_STATUS_E_RESOURCES)
+ cfg80211_err("HO is in progress.So defer the scan by informing busy");
+ }
+ } else {
+ ucfg_scm_scan_free_scan_request_mem(scan_start_req);
+ status = QDF_STATUS_E_RESOURCES;
+ }
+
qdf_mutex_release(&osif_scan->scan_req_q_lock);
if (QDF_STATUS_SUCCESS != status) {
cfg80211_err("Failed to enqueue Scan Req");
@@ -1310,7 +1326,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev,
wlan_scan_id scan_id;
bool is_p2p_scan = false;
enum wlan_band band;
- struct net_device *netdev = NULL;
QDF_STATUS qdf_status;
/* Get the vdev object */
@@ -1539,10 +1554,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev,
if (request->flags & NL80211_SCAN_FLAG_FLUSH)
ucfg_scan_flush_results(pdev, NULL);
- /* Enqueue the scan request */
- 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
@@ -1556,18 +1567,15 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev,
qdf_runtime_pm_prevent_suspend(
&osif_priv->osif_scan->runtime_pm_lock);
- qdf_status = ucfg_scan_start(req);
+ qdf_status = wlan_schedule_scan_start_request(pdev, request,
+ params->source, req);
if (QDF_IS_STATUS_ERROR(qdf_status)) {
- cfg80211_err("ucfg_scan_start returned error %d", qdf_status);
- if (qdf_status == QDF_STATUS_E_RESOURCES)
- 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)) {
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);
+ &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);
diff --git a/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h b/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h
index 215c6f234..8f1db070b 100644
--- a/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h
+++ b/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h
@@ -188,6 +188,14 @@ ucfg_scan_get_pno_match(struct wlan_objmgr_vdev *vdev)
}
#endif /* FEATURE_WLAN_SCAN_PNO */
/**
+ * ucfg_scm_scan_free_scan_request_mem() - Free scan request memory
+ * @req: scan_start_request object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_scm_scan_free_scan_request_mem(struct scan_start_request *req);
+
+/**
* ucfg_scan_start() - Public API to start a scan
* @req: start scan req params
*
diff --git a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c
index e3a927f83..edb6259a7 100644
--- a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c
+++ b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c
@@ -1006,6 +1006,12 @@ ucfg_scan_req_update_params(struct wlan_objmgr_vdev *vdev,
}
QDF_STATUS
+ucfg_scm_scan_free_scan_request_mem(struct scan_start_request *req)
+{
+ return scm_scan_free_scan_request_mem(req);
+}
+
+QDF_STATUS
ucfg_scan_start(struct scan_start_request *req)
{
struct scheduler_msg msg = {0};