Przeglądaj źródła

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
Guisen Yang 4 lat temu
rodzic
commit
3516552a3c

+ 16 - 1
target_if/scan/src/target_if_scan.c

@@ -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
  * 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
 
+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
 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->pno_start = target_if_pno_start;
 	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_unreg_ev_handler = target_if_scan_unregister_event_handler;
 

+ 3 - 0
umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h

@@ -241,6 +241,7 @@ struct wlan_lmac_if_mgmt_txrx_tx_ops {
  * @scan_cancel: function to cancel scan
  * @pno_start: start pno scan
  * @pno_stop: stop pno scan
+ * @obss_disable: disable obss scan
  * @scan_reg_ev_handler: function to register 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);
 	QDF_STATUS (*pno_stop)(struct wlan_objmgr_psoc *psoc,
 			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,
 			void *arg);
 	QDF_STATUS (*scan_unreg_ev_handler)(struct wlan_objmgr_psoc *psoc,

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

@@ -508,6 +508,7 @@ struct scan_cb {
  * @miracast_enabled: miracast enabled
  * @disable_timeout: command timeout disabled
  * @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)
  * @scan_start_request_buff: buffer used to pass
  *      scan config to event handlers
@@ -541,6 +542,7 @@ struct wlan_scan_obj {
 	bool disable_timeout;
 	bool drop_bcn_on_chan_mismatch;
 	bool drop_bcn_on_invalid_freq;
+	bool obss_scan_offload;
 	struct scan_start_request scan_start_request_buff;
 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
 	struct channel_list_db rnr_channel_db;

+ 33 - 0
umac/scan/core/src/wlan_scan_manager.c

@@ -1629,3 +1629,36 @@ QDF_STATUS scm_scan_cancel_flush_callback(struct scheduler_msg *msg)
 
 	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);
+	}
+}

+ 11 - 1
umac/scan/core/src/wlan_scan_manager.h

@@ -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
  * 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);
 
+/**
+ * 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

+ 10 - 1
umac/scan/dispatcher/inc/wlan_scan_tgt_api.h

@@ -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
  * 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
 
+/**
+ * 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
  * @req: scan request object

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

@@ -266,6 +266,15 @@ QDF_STATUS
 ucfg_scan_get_global_config(struct wlan_objmgr_psoc *psoc,
 		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
  * @pdev: psoc on which scans need to be disabled

+ 29 - 1
umac/scan/dispatcher/src/wlan_scan_tgt_api.c

@@ -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
  * 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
 
+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
 tgt_scan_start(struct scan_start_request *req)
 {

+ 18 - 2
umac/scan/dispatcher/src/wlan_scan_ucfg_api.c

@@ -753,6 +753,7 @@ wlan_scan_global_init(struct wlan_objmgr_psoc *psoc,
 	scan_obj->drop_bcn_on_invalid_freq =
 			 cfg_get(psoc, CFG_DROP_BCN_ON_INVALID_FREQ);
 	scan_obj->disable_timeout = false;
+	scan_obj->obss_scan_offload = false;
 	scan_obj->scan_def.active_dwell =
 			 cfg_get(psoc, CFG_ACTIVE_MAX_CHANNEL_TIME);
 	/* 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;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	int i;
-
 	ucfg_scan_psoc_set_disable(psoc, REASON_SUSPEND);
+
 	/* Check all pdev */
 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
 		pdev = wlan_objmgr_get_pdev_by_id(psoc, i, WLAN_SCAN_ID);
 		if (!pdev)
 			continue;
 		if (ucfg_scan_get_pdev_status(pdev) !=
-		    SCAN_NOT_IN_PROGRESS)
+		    SCAN_NOT_IN_PROGRESS) {
 			status = ucfg_scan_cancel_pdev_scan(pdev);
+			scm_disable_obss_pdev_scan(psoc, pdev);
+		}
 		wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
 		if (QDF_IS_STATUS_ERROR(status)) {
 			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;
 }
 
+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
 bool ucfg_scan_is_pno_offload_enabled(struct wlan_objmgr_psoc *psoc)
 {

+ 12 - 0
wmi/inc/wmi_unified_api.h

@@ -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);
 
+/**
+ * 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
 /**
  * wmi_unified_pno_start_cmd() - PNO start request

+ 2 - 0
wmi/inc/wmi_unified_priv.h

@@ -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,
 		   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,
 		struct nlo_mawc_params *params);
 

+ 10 - 0
wmi/src/wmi_unified_api.c

@@ -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;
 }
 
+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
 QDF_STATUS wmi_unified_pno_start_cmd(wmi_unified_t wmi_handle,
 				     struct pno_scan_req_params *pno)

+ 39 - 0
wmi/src/wmi_unified_tlv.c

@@ -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;
 }
 
+/**
+ * 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
  * @buf_ptr:      Buffer passed by upper layers
@@ -15005,6 +15043,7 @@ struct wmi_ops tlv_ops =  {
 #endif
 	.send_pno_stop_cmd = send_pno_stop_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,
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
 	.send_process_ll_stats_clear_cmd = send_process_ll_stats_clear_cmd_tlv,