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
Этот коммит содержится в:

коммит произвёл
snandini

родитель
de26e8e65e
Коммит
1081eb4b63
@@ -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,
|
||||
static int
|
||||
wlan_schedule_scan_start_request(struct wlan_objmgr_pdev *pdev,
|
||||
struct cfg80211_scan_request *req,
|
||||
uint8_t source, uint32_t scan_id)
|
||||
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,
|
||||
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
|
||||
} 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,17 +1566,14 @@ 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,
|
||||
¶ms->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,
|
||||
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,
|
||||
¶ms->source, &netdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -162,6 +162,14 @@ ucfg_scan_get_pno_match(struct wlan_objmgr_vdev *vdev)
|
||||
return false;
|
||||
}
|
||||
#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
|
||||
|
@@ -429,6 +429,12 @@ ucfg_scan_set_custom_scan_chan_list(struct wlan_objmgr_pdev *pdev,
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
Ссылка в новой задаче
Block a user