qcacmn: Disable obss scan before suspend

When obss scan is enabled, FW will trigger scan periodically by
a timer. If a scan was triggered, FW need to access host memory
for data transfer. Occasionally, suspend may happen during one
scan, then FW is unable to access host memory and fw will crash.
So disable the obss scan before suspend.

Change-Id: Ie507da929a3701473cb57888e96e702e34d4c95a
CRs-Fixed: 2927239
This commit is contained in:
Guisen Yang
2021-04-19 17:17:26 +08:00
committed by Madan Koyyalamudi
parent 841fa1bd6a
commit 3516552a3c
13 changed files with 194 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for * Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the * any purpose with or without fee is hereby granted, provided that the
@@ -357,6 +357,20 @@ target_if_pno_stop(struct wlan_objmgr_psoc *psoc,
} }
#endif #endif
static QDF_STATUS
target_if_obss_scan_disable(struct wlan_objmgr_psoc *psoc,
uint8_t vdev_id)
{
struct wmi_unified *wmi_handle;
wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
if (!wmi_handle) {
target_if_err("Invalid WMI handle");
return QDF_STATUS_E_FAILURE;
}
return wmi_unified_obss_disable_cmd(wmi_handle, vdev_id);
}
QDF_STATUS QDF_STATUS
target_if_scan_register_event_handler(struct wlan_objmgr_psoc *psoc, void *arg) target_if_scan_register_event_handler(struct wlan_objmgr_psoc *psoc, void *arg)
@@ -453,6 +467,7 @@ target_if_scan_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops)
scan->scan_cancel = target_if_scan_cancel; scan->scan_cancel = target_if_scan_cancel;
scan->pno_start = target_if_pno_start; scan->pno_start = target_if_pno_start;
scan->pno_stop = target_if_pno_stop; scan->pno_stop = target_if_pno_stop;
scan->obss_disable = target_if_obss_scan_disable;
scan->scan_reg_ev_handler = target_if_scan_register_event_handler; scan->scan_reg_ev_handler = target_if_scan_register_event_handler;
scan->scan_unreg_ev_handler = target_if_scan_unregister_event_handler; scan->scan_unreg_ev_handler = target_if_scan_unregister_event_handler;

View File

@@ -241,6 +241,7 @@ struct wlan_lmac_if_mgmt_txrx_tx_ops {
* @scan_cancel: function to cancel scan * @scan_cancel: function to cancel scan
* @pno_start: start pno scan * @pno_start: start pno scan
* @pno_stop: stop pno scan * @pno_stop: stop pno scan
* @obss_disable: disable obss scan
* @scan_reg_ev_handler: function to register for scan events * @scan_reg_ev_handler: function to register for scan events
* @scan_unreg_ev_handler: function to unregister for scan events * @scan_unreg_ev_handler: function to unregister for scan events
* *
@@ -255,6 +256,8 @@ struct wlan_lmac_if_scan_tx_ops {
struct pno_scan_req_params *req); struct pno_scan_req_params *req);
QDF_STATUS (*pno_stop)(struct wlan_objmgr_psoc *psoc, QDF_STATUS (*pno_stop)(struct wlan_objmgr_psoc *psoc,
uint8_t vdev_id); uint8_t vdev_id);
QDF_STATUS (*obss_disable)(struct wlan_objmgr_psoc *psoc,
uint8_t vdev_id);
QDF_STATUS (*scan_reg_ev_handler)(struct wlan_objmgr_psoc *psoc, QDF_STATUS (*scan_reg_ev_handler)(struct wlan_objmgr_psoc *psoc,
void *arg); void *arg);
QDF_STATUS (*scan_unreg_ev_handler)(struct wlan_objmgr_psoc *psoc, QDF_STATUS (*scan_unreg_ev_handler)(struct wlan_objmgr_psoc *psoc,

View File

@@ -508,6 +508,7 @@ struct scan_cb {
* @miracast_enabled: miracast enabled * @miracast_enabled: miracast enabled
* @disable_timeout: command timeout disabled * @disable_timeout: command timeout disabled
* @drop_bcn_on_chan_mismatch: drop bcn if channel mismatch * @drop_bcn_on_chan_mismatch: drop bcn if channel mismatch
* @obss_scan_offload: if obss scan offload is enabled
* @drop_bcn_on_invalid_freq: drop bcn if freq is invalid in IEs (DS/HT/HE) * @drop_bcn_on_invalid_freq: drop bcn if freq is invalid in IEs (DS/HT/HE)
* @scan_start_request_buff: buffer used to pass * @scan_start_request_buff: buffer used to pass
* scan config to event handlers * scan config to event handlers
@@ -541,6 +542,7 @@ struct wlan_scan_obj {
bool disable_timeout; bool disable_timeout;
bool drop_bcn_on_chan_mismatch; bool drop_bcn_on_chan_mismatch;
bool drop_bcn_on_invalid_freq; bool drop_bcn_on_invalid_freq;
bool obss_scan_offload;
struct scan_start_request scan_start_request_buff; struct scan_start_request scan_start_request_buff;
#ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
struct channel_list_db rnr_channel_db; struct channel_list_db rnr_channel_db;

View File

@@ -1629,3 +1629,36 @@ QDF_STATUS scm_scan_cancel_flush_callback(struct scheduler_msg *msg)
return QDF_STATUS_SUCCESS; return QDF_STATUS_SUCCESS;
} }
void scm_disable_obss_pdev_scan(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{
struct wlan_objmgr_vdev *vdev;
struct wlan_scan_obj *scan_obj;
struct scan_vdev_obj *scan_vdev_obj;
QDF_STATUS status;
scan_obj = wlan_psoc_get_scan_obj(psoc);
if (!scan_obj) {
scm_err("scan object null");
return;
}
if (scan_obj->obss_scan_offload) {
vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_SCAN_ID);
if (!vdev)
return;
scan_vdev_obj = wlan_get_vdev_scan_obj(vdev);
if (!scan_vdev_obj) {
scm_err("null scan_vdev_obj");
wlan_objmgr_vdev_release_ref(vdev, WLAN_SCAN_ID);
return;
}
status = tgt_scan_obss_disable(vdev);
if (QDF_IS_STATUS_ERROR(status))
scm_err("disable obss scan failed");
wlan_objmgr_vdev_release_ref(vdev, WLAN_SCAN_ID);
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. * Copyright (c) 2017-2018, 2020-2021 The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for * Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the * any purpose with or without fee is hereby granted, provided that the
@@ -128,4 +128,14 @@ QDF_STATUS scm_scan_start_flush_callback(struct scheduler_msg *msg);
*/ */
QDF_STATUS scm_scan_cancel_flush_callback(struct scheduler_msg *msg); QDF_STATUS scm_scan_cancel_flush_callback(struct scheduler_msg *msg);
/**
* scm_disable_obss_pdev_scan() - Public API to disable pdev obss scan
* @psoc: psoc pointer
* @pdev: pdev pointer
*
* Return: void
*/
void scm_disable_obss_pdev_scan(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev);
#endif #endif

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017 The Linux Foundation. All rights reserved. * Copyright (c) 2017,2021 The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for * Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the * any purpose with or without fee is hereby granted, provided that the
@@ -86,6 +86,15 @@ QDF_STATUS tgt_scan_pno_stop(struct wlan_objmgr_vdev *vdev,
#endif #endif
/**
* tgt_scan_obss_disable() - invoke lmac disable obss scan req
* @vdev: vdev pointer
*
*
* Return: QDF_STATUS_SUCCESS for success or error code.
*/
QDF_STATUS tgt_scan_obss_disable(struct wlan_objmgr_vdev *vdev);
/** /**
* tgt_scan_start() - invoke lmac scan start * tgt_scan_start() - invoke lmac scan start
* @req: scan request object * @req: scan request object

View File

@@ -266,6 +266,15 @@ QDF_STATUS
ucfg_scan_get_global_config(struct wlan_objmgr_psoc *psoc, ucfg_scan_get_global_config(struct wlan_objmgr_psoc *psoc,
enum scan_config config, uint32_t *val); enum scan_config config, uint32_t *val);
/**
* ucfg_scan_set_obss_scan_offload() - Public API to set obss scan flag
* @psoc: psoc context
* @val: the value to be set
*
* Return: void.
*/
void ucfg_scan_set_obss_scan_offload(struct wlan_objmgr_psoc *psoc, bool value);
/** /**
* ucfg_scan_set_wide_band_scan() - Public API to disable/enable wide band scan * ucfg_scan_set_wide_band_scan() - Public API to disable/enable wide band scan
* @pdev: psoc on which scans need to be disabled * @pdev: psoc on which scans need to be disabled

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for * Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the * any purpose with or without fee is hereby granted, provided that the
@@ -135,6 +135,34 @@ QDF_STATUS tgt_scan_pno_stop(struct wlan_objmgr_vdev *vdev,
} }
#endif #endif
QDF_STATUS tgt_scan_obss_disable(struct wlan_objmgr_vdev *vdev)
{
struct wlan_lmac_if_scan_tx_ops *scan_ops;
struct wlan_objmgr_psoc *psoc;
uint8_t vdev_id;
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
scm_err("NULL PSOC");
return QDF_STATUS_E_FAILURE;
}
scan_ops = wlan_psoc_get_scan_txops(psoc);
if (!scan_ops) {
scm_err("NULL scan_ops");
return QDF_STATUS_E_FAILURE;
}
vdev_id = wlan_vdev_get_id(vdev);
/* invoke wmi_unified_obss_disable_cmd() */
QDF_ASSERT(scan_ops->obss_disable);
if (scan_ops->obss_disable)
return scan_ops->obss_disable(psoc, vdev_id);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS QDF_STATUS
tgt_scan_start(struct scan_start_request *req) tgt_scan_start(struct scan_start_request *req)
{ {

View File

@@ -753,6 +753,7 @@ wlan_scan_global_init(struct wlan_objmgr_psoc *psoc,
scan_obj->drop_bcn_on_invalid_freq = scan_obj->drop_bcn_on_invalid_freq =
cfg_get(psoc, CFG_DROP_BCN_ON_INVALID_FREQ); cfg_get(psoc, CFG_DROP_BCN_ON_INVALID_FREQ);
scan_obj->disable_timeout = false; scan_obj->disable_timeout = false;
scan_obj->obss_scan_offload = false;
scan_obj->scan_def.active_dwell = scan_obj->scan_def.active_dwell =
cfg_get(psoc, CFG_ACTIVE_MAX_CHANNEL_TIME); cfg_get(psoc, CFG_ACTIVE_MAX_CHANNEL_TIME);
/* the ini is disallow DFS channel scan if ini is 1, so negate that */ /* the ini is disallow DFS channel scan if ini is 1, so negate that */
@@ -1308,16 +1309,18 @@ ucfg_scan_suspend_handler(struct wlan_objmgr_psoc *psoc, void *arg)
struct wlan_objmgr_pdev *pdev = NULL; struct wlan_objmgr_pdev *pdev = NULL;
QDF_STATUS status = QDF_STATUS_SUCCESS; QDF_STATUS status = QDF_STATUS_SUCCESS;
int i; int i;
ucfg_scan_psoc_set_disable(psoc, REASON_SUSPEND); ucfg_scan_psoc_set_disable(psoc, REASON_SUSPEND);
/* Check all pdev */ /* Check all pdev */
for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
pdev = wlan_objmgr_get_pdev_by_id(psoc, i, WLAN_SCAN_ID); pdev = wlan_objmgr_get_pdev_by_id(psoc, i, WLAN_SCAN_ID);
if (!pdev) if (!pdev)
continue; continue;
if (ucfg_scan_get_pdev_status(pdev) != if (ucfg_scan_get_pdev_status(pdev) !=
SCAN_NOT_IN_PROGRESS) SCAN_NOT_IN_PROGRESS) {
status = ucfg_scan_cancel_pdev_scan(pdev); status = ucfg_scan_cancel_pdev_scan(pdev);
scm_disable_obss_pdev_scan(psoc, pdev);
}
wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID); wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
if (QDF_IS_STATUS_ERROR(status)) { if (QDF_IS_STATUS_ERROR(status)) {
scm_err("failed to cancel scan for pdev_id %d", i); scm_err("failed to cancel scan for pdev_id %d", i);
@@ -1690,6 +1693,19 @@ ucfg_scan_get_global_config(struct wlan_objmgr_psoc *psoc,
return status; return status;
} }
void ucfg_scan_set_obss_scan_offload(struct wlan_objmgr_psoc *psoc, bool value)
{
struct wlan_scan_obj *scan_obj;
scan_obj = wlan_psoc_get_scan_obj(psoc);
if (!scan_obj) {
scm_err("NULL scan obj");
return;
}
scan_obj->obss_scan_offload = value;
}
#ifdef FEATURE_WLAN_SCAN_PNO #ifdef FEATURE_WLAN_SCAN_PNO
bool ucfg_scan_is_pno_offload_enabled(struct wlan_objmgr_psoc *psoc) bool ucfg_scan_is_pno_offload_enabled(struct wlan_objmgr_psoc *psoc)
{ {

View File

@@ -1431,6 +1431,18 @@ wmi_unified_ipa_offload_control_cmd(
*/ */
QDF_STATUS wmi_unified_pno_stop_cmd(wmi_unified_t wmi_handle, uint8_t vdev_id); QDF_STATUS wmi_unified_pno_stop_cmd(wmi_unified_t wmi_handle, uint8_t vdev_id);
/**
* wmi_unified_obss_disable_cmd() - disable obss scan request
* @wmi_handle: wmi handle
* @vdev_id: vdev id
*
* This function request FW to disable obss scan.
*
* Return: QDF_STATUS_SUCCESS on success and others for failure
*/
QDF_STATUS wmi_unified_obss_disable_cmd(wmi_unified_t wmi_handle,
uint8_t vdev_id);
#ifdef FEATURE_WLAN_SCAN_PNO #ifdef FEATURE_WLAN_SCAN_PNO
/** /**
* wmi_unified_pno_start_cmd() - PNO start request * wmi_unified_pno_start_cmd() - PNO start request

View File

@@ -798,6 +798,8 @@ QDF_STATUS (*send_pno_stop_cmd)(wmi_unified_t wmi_handle, uint8_t vdev_id);
QDF_STATUS (*send_pno_start_cmd)(wmi_unified_t wmi_handle, QDF_STATUS (*send_pno_start_cmd)(wmi_unified_t wmi_handle,
struct pno_scan_req_params *pno); struct pno_scan_req_params *pno);
QDF_STATUS (*send_obss_disable_cmd)(wmi_unified_t wmi_handle, uint8_t vdev_id);
QDF_STATUS (*send_nlo_mawc_cmd)(wmi_unified_t wmi_handle, QDF_STATUS (*send_nlo_mawc_cmd)(wmi_unified_t wmi_handle,
struct nlo_mawc_params *params); struct nlo_mawc_params *params);

View File

@@ -727,6 +727,16 @@ QDF_STATUS wmi_unified_pno_stop_cmd(wmi_unified_t wmi_handle, uint8_t vdev_id)
return QDF_STATUS_E_FAILURE; return QDF_STATUS_E_FAILURE;
} }
QDF_STATUS wmi_unified_obss_disable_cmd(wmi_unified_t wmi_handle,
uint8_t vdev_id)
{
if (wmi_handle->ops->send_obss_disable_cmd)
return wmi_handle->ops->send_obss_disable_cmd(wmi_handle,
vdev_id);
return QDF_STATUS_E_FAILURE;
}
#ifdef FEATURE_WLAN_SCAN_PNO #ifdef FEATURE_WLAN_SCAN_PNO
QDF_STATUS wmi_unified_pno_start_cmd(wmi_unified_t wmi_handle, QDF_STATUS wmi_unified_pno_start_cmd(wmi_unified_t wmi_handle,
struct pno_scan_req_params *pno) struct pno_scan_req_params *pno)

View File

@@ -4877,6 +4877,44 @@ static QDF_STATUS send_pno_stop_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_i
return QDF_STATUS_SUCCESS; return QDF_STATUS_SUCCESS;
} }
/**
* send_obss_disable_cmd_tlv() - disable obss scan request
* @wmi_handle: wmi handle
* @vdev_id: vdev id
*
* This function request FW to disable ongoing obss scan operation.
*
* Return: QDF status
*/
static QDF_STATUS send_obss_disable_cmd_tlv(wmi_unified_t wmi_handle,
uint8_t vdev_id)
{
QDF_STATUS status;
wmi_buf_t buf;
wmi_obss_scan_disable_cmd_fixed_param *cmd;
int len = sizeof(*cmd);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf)
return QDF_STATUS_E_NOMEM;
wmi_debug("cmd %x vdev_id %d", WMI_OBSS_SCAN_DISABLE_CMDID, vdev_id);
cmd = (wmi_obss_scan_disable_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_obss_scan_disable_cmd_fixed_param));
cmd->vdev_id = vdev_id;
status = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_OBSS_SCAN_DISABLE_CMDID);
if (QDF_IS_STATUS_ERROR(status))
wmi_buf_free(buf);
return status;
}
/** /**
* wmi_set_pno_channel_prediction() - Set PNO channel prediction * wmi_set_pno_channel_prediction() - Set PNO channel prediction
* @buf_ptr: Buffer passed by upper layers * @buf_ptr: Buffer passed by upper layers
@@ -15005,6 +15043,7 @@ struct wmi_ops tlv_ops = {
#endif #endif
.send_pno_stop_cmd = send_pno_stop_cmd_tlv, .send_pno_stop_cmd = send_pno_stop_cmd_tlv,
.send_pno_start_cmd = send_pno_start_cmd_tlv, .send_pno_start_cmd = send_pno_start_cmd_tlv,
.send_obss_disable_cmd = send_obss_disable_cmd_tlv,
.send_nlo_mawc_cmd = send_nlo_mawc_cmd_tlv, .send_nlo_mawc_cmd = send_nlo_mawc_cmd_tlv,
#ifdef WLAN_FEATURE_LINK_LAYER_STATS #ifdef WLAN_FEATURE_LINK_LAYER_STATS
.send_process_ll_stats_clear_cmd = send_process_ll_stats_clear_cmd_tlv, .send_process_ll_stats_clear_cmd = send_process_ll_stats_clear_cmd_tlv,