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
此提交包含在:
Bapiraju Alla
2020-06-26 15:29:47 +05:30
提交者 snandini
父節點 de26e8e65e
當前提交 1081eb4b63
共有 3 個檔案被更改,包括 47 行新增33 行删除

查看文件

@@ -649,20 +649,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;
@@ -670,23 +672,35 @@ static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev,
struct osif_scan_pdev *osif_scan;
scan_req = qdf_mem_malloc(sizeof(*scan_req));
if (!scan_req)
if (!scan_req) {
ucfg_scm_scan_free_scan_request_mem(scan_start_req);
return -ENOMEM;
}
/* Get NL global context from objmgr*/
osif_ctx = wlan_pdev_get_ospriv(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);
if (qdf_list_size(&osif_scan->scan_req_q) < WLAN_MAX_SCAN_COUNT)
status = qdf_list_insert_back(&osif_scan->scan_req_q,
&scan_req->node);
else
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 {
osif_err("scan req failed with error %d", status);
if (status == QDF_STATUS_E_RESOURCES)
osif_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_IS_STATUS_ERROR(status)) {
osif_rl_debug("Failed to enqueue Scan Req as max scan %d already queued",
@@ -1291,7 +1305,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
wlan_scan_id scan_id;
bool is_p2p_scan = false;
enum wlan_band band;
struct net_device *netdev = NULL;
QDF_STATUS qdf_status;
enum QDF_OPMODE opmode;
uint32_t extra_ie_len = 0;
@@ -1346,14 +1359,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
req->scan_req.scan_id = scan_id;
req->scan_req.scan_req_id = req_id;
/* Enqueue the scan request */
ret = wlan_scan_request_enqueue(pdev, request, params->source,
req->scan_req.scan_id);
if (ret) {
qdf_mem_free(req);
return ret;
}
/* Update scan policy type flags according to cfg scan request */
wlan_cfg80211_update_scan_policy_type_flags(request,
&req->scan_req);
@@ -1561,18 +1566,15 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
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)) {
osif_err("scan req failed with error %d", qdf_status);
if (qdf_status == QDF_STATUS_E_RESOURCES)
osif_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);
}
}
@@ -1580,8 +1582,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
err:
qdf_mem_free(req);
wlan_scan_request_dequeue(pdev, scan_id, &request,
&params->source, &netdev);
return ret;
}