Procházet zdrojové kódy

qcacmn: scan convergence - interface definition

Add north interface, south interface and offload interface
API definitions

Change-Id: Iccae20d266e7248088241416730d9ea317c3f77b
CRs-Fixed: 1095299
Om Prakash Tripathi před 8 roky
rodič
revize
22f95dcc59

+ 75 - 0
target_if/scan/inc/target_if_scan.h

@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: offload lmac interface APIs for scan
+ */
+#ifndef __TARGET_SCAN_IF_H__
+#define __TARGET_SCAN_IF_H__
+
+struct scan_req_params;
+struct scan_cancel_param;
+struct wlan_objmgr_psoc;
+
+/**
+ * target_if_scan_register_event_handler() - lmac handler API
+ * to register for scan events
+ * @psoc: psoc object
+ * @arg: argument to lmac
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_scan_register_event_handler(struct wlan_objmgr_psoc *psoc,
+		void *arg);
+
+/**
+ * target_if_scan_unregister_event_handler() - lmac handler API
+ * to unregister for scan events
+ * @psoc: psoc object
+ * @arg: argument to lmac
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_scan_unregister_event_handler(struct wlan_objmgr_psoc *psoc,
+		void *arg);
+
+/**
+ * target_if_scan_start() - lmac handler API to start scan
+ * @psoc: psoc object
+ * @req: scan_req_params object
+ *
+ * Return: QDF_STATUS
+ */
+
+QDF_STATUS
+target_if_scan_start(struct wlan_objmgr_psoc *psoc,
+		struct scan_start_request *req);
+
+/**
+ * target_if_scan_cancel() - lmac handler API to cancel a previous active scan
+ * @psoc: psoc object
+ * @req: scan_cancel_param object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_scan_cancel(struct wlan_objmgr_psoc *psoc,
+		struct scan_cancel_param *req);
+#endif

+ 115 - 0
target_if/scan/src/target_if_scan.c

@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: offload lmac interface APIs definitions for scan
+ */
+
+#include <qdf_mem.h>
+#include <qdf_status.h>
+#include <wmi_unified_api.h>
+#include <wmi_unified_priv.h>
+#include <wmi_unified_param.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_scan_tgt_api.h>
+#include <target_if.h>
+
+static inline struct wlan_lmac_if_scan_rx_ops *
+target_if_scan_get_rx_ops(struct wlan_objmgr_psoc *psoc)
+{
+	return &psoc->soc_cb.rx_ops.scan;
+}
+
+static int
+target_if_scan_event_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen)
+{
+	struct scan_event_info *event_info;
+	struct wlan_objmgr_psoc *psoc;
+	struct wmi_unified *wmi_handle;
+	struct wlan_lmac_if_scan_rx_ops *scan_rx_ops;
+	QDF_STATUS status;
+
+	if (!scn || !data) {
+		target_if_err("scn: 0x%p, data: 0x%p\n", scn, data);
+		return -EINVAL;
+	}
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("null psoc\n");
+		return -EINVAL;
+	}
+	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
+
+	event_info = qdf_mem_malloc(sizeof(*event_info));
+
+	if (!event_info) {
+		target_if_err("%s: unable to allocate scan_event\n", __func__);
+		return -ENOMEM;
+	}
+
+	if (wmi_extract_vdev_scan_ev_param(wmi_handle, data,
+			&(event_info->event))) {
+		target_if_err("%s: Failed to extract wmi scan event\n",
+			__func__);
+		qdf_mem_free(event_info);
+		return -EINVAL;
+	}
+
+	scan_rx_ops = target_if_scan_get_rx_ops(psoc);
+	if (scan_rx_ops->scan_ev_handler) {
+		status = scan_rx_ops->scan_ev_handler(psoc, event_info);
+		if (status != QDF_STATUS_SUCCESS) {
+			qdf_mem_free(event_info);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+QDF_STATUS
+target_if_scan_register_event_handler(struct wlan_objmgr_psoc *psoc, void *arg)
+{
+	return wmi_unified_register_event_handler(psoc->tgt_if_handle,
+		wmi_scan_event_id, target_if_scan_event_handler,
+		WMI_RX_UMAC_CTX);
+}
+
+QDF_STATUS
+target_if_scan_unregister_event_handler(struct wlan_objmgr_psoc *psoc,
+		void *arg)
+{
+	return wmi_unified_unregister_event_handler(psoc->tgt_if_handle,
+		wmi_scan_event_id);
+}
+
+QDF_STATUS
+target_if_scan_start(struct wlan_objmgr_psoc *psoc,
+		struct scan_start_request *req)
+{
+	return wmi_unified_scan_start_cmd_send(psoc->tgt_if_handle,
+		&req->scan_req);
+}
+
+
+QDF_STATUS
+target_if_scan_cancel(struct wlan_objmgr_psoc *psoc,
+		struct scan_cancel_param *req)
+{
+	return wmi_unified_scan_stop_cmd_send(psoc->tgt_if_handle, req);
+}

+ 2 - 0
umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h

@@ -164,6 +164,7 @@ typedef void (*wlan_objmgr_peer_status_handler)(
  * @WLAN_SERIALIZATION_ID:      Serialization operations
  * @WLAN_PMO_ID:                power manager offload (PMO) ID
  * @WLAN_LEGACY_SME_ID:         Legacy SME operations
+ * @WLAN_SCAN_ID:               scan operations
  * @WLAN_REF_ID_MAX:            Max id used to generate ref count tracking array
  */
 typedef enum {
@@ -179,6 +180,7 @@ typedef enum {
 	WLAN_SERIALIZATION_ID = 9,
 	WLAN_PMO_ID           = 10,
 	WLAN_LEGACY_SME_ID    = 11,
+	WLAN_SCAN_ID          = 12,
 	WLAN_REF_ID_MAX,
 } wlan_objmgr_ref_dbgid;
 

+ 41 - 14
umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h

@@ -23,6 +23,7 @@
 #include "qdf_status.h"
 #include "wlan_objmgr_cmn.h"
 #include "wlan_mgmt_txrx_utils_api.h"
+#include "wlan_scan_public_structs.h"
 
 /* Number of dev type: Direct attach and Offload */
 #define MAX_DEV_TYPE 2
@@ -42,10 +43,46 @@ struct wlan_lmac_if_mgmt_txrx_tx_ops {
 			qdf_nbuf_t nbuf);
 };
 
+
+/**
+ * struct wlan_lmac_if_scan_tx_ops - south bound tx function pointers for scan
+ * @scan_start: function to start scan
+ * @scan_cancel: function to cancel scan
+ * @scan_reg_ev_handler: function to register for scan events
+ * @scan_unreg_ev_handler: function to unregister for scan events
+ *
+ * scan module uses these functions to avail ol/da lmac services
+ */
+struct wlan_lmac_if_scan_tx_ops {
+	QDF_STATUS (*scan_start)(struct wlan_objmgr_psoc *psoc,
+			struct scan_start_request *req);
+	QDF_STATUS (*scan_cancel)(struct wlan_objmgr_psoc *psoc,
+			struct scan_cancel_param *req);
+	QDF_STATUS (*scan_reg_ev_handler)(struct wlan_objmgr_psoc *psoc,
+			void *arg);
+	QDF_STATUS (*scan_unreg_ev_handler)(struct wlan_objmgr_psoc *psoc,
+			void *arg);
+	QDF_STATUS (*set_chan_list)(struct wlan_objmgr_pdev *pdev, void *arg);
+};
+
+
+/**
+ * struct wlan_lmac_if_scan_rx_ops  - south bound rx function pointers for scan
+ * @scan_ev_handler: scan event handler
+ *
+ * lmac modules uses this API to post scan events to scan module
+ */
+struct wlan_lmac_if_scan_rx_ops {
+	QDF_STATUS (*scan_ev_handler)(struct wlan_objmgr_psoc *psoc,
+		struct scan_event_info *event_info);
+};
+
+
 /**
  * struct wlan_lmac_if_tx_ops - south bound tx function pointers
- * @arg1
- * @arg2
+ * @mgmt_txrx_tx_ops: mgmt txrx tx ops
+ * @scan: scan tx ops
+ * @set_chan_list: tx func for configuring scan channel
  *
  * Callback function tabled to be registered with umac.
  * umac will use the functional table to send events/frames to lmac/wmi
@@ -54,16 +91,11 @@ struct wlan_lmac_if_mgmt_txrx_tx_ops {
 struct wlan_lmac_if_tx_ops {
 	/* Components to declare function pointers required by the module
 	 * in component specific structure.
-	 * Ex : scan module
-	 * struct wlan_lmac_if_scan_tx_ops scan_tx_ops;
 	 * The component specific ops structure can be declared in this file
 	 * only
-	 * struct wlan_lmac_if_scan_tx_ops {
-	 *	int (*fp1)();
-	 *	void (*fp2)();
-	 * }
 	 */
 	 struct wlan_lmac_if_mgmt_txrx_tx_ops mgmt_txrx_tx_ops;
+	 struct wlan_lmac_if_scan_tx_ops scan;
 };
 
 /**
@@ -107,16 +139,11 @@ struct wlan_lmac_if_mgmt_txrx_rx_ops {
 struct wlan_lmac_if_rx_ops {
 	/* Components to declare function pointers required by the module
 	 * in component specific structure.
-	 * Ex : scan module
-	 * struct wlan_lmac_if_scan_rx_ops scan_rx_ops;
 	 * The component specific ops structure can be declared in this file
 	 * only
-	 * struct wlan_lmac_if_scan_rx_ops {
-	 *	int (*fp1)();
-	 *	void (*fp2)();
-	 * }
 	 */
 	 struct wlan_lmac_if_mgmt_txrx_rx_ops mgmt_txrx_rx_ops;
+	 struct wlan_lmac_if_scan_rx_ops scan;
 };
 
 /* Function pointer to call legacy tx_ops registration in OL/WMA.

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

@@ -24,6 +24,8 @@
 #define _WLAN_SCAN_MAIN_API_H_
 
 #include <qdf_atomic.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
 #include <wlan_objmgr_vdev_obj.h>
 #include <wlan_scan_public_structs.h>
 #include "wlan_scan_cache_db.h"

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

@@ -19,3 +19,492 @@
 /*
  * DOC: contains scan manager functionality
  */
+
+#include <wlan_serialization_api.h>
+#include <wlan_scan_ucfg_api.h>
+#include <wlan_scan_tgt_api.h>
+#include "wlan_scan_main.h"
+#include "wlan_scan_manager.h"
+
+static QDF_STATUS
+scm_free_scan_request_mem(struct scan_start_request *req)
+{
+	void *ie;
+
+	if (!req) {
+		scm_err("null request");
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_FAILURE;
+	}
+	scm_info("freed scan request: 0x%p, scan_id: %d, requester: %d",
+		req, req->scan_req.scan_id, req->scan_req.scan_req_id);
+	/* Free vendor(extra) ie */
+	ie = req->scan_req.extraie.ptr;
+	if (ie) {
+		req->scan_req.extraie.ptr = NULL;
+		req->scan_req.extraie.len = 0;
+		qdf_mem_free(ie);
+	}
+
+	/* Free htcap ie */
+	ie = req->scan_req.htcap.ptr;
+	if (ie) {
+		req->scan_req.htcap.len = 0;
+		req->scan_req.htcap.ptr = NULL;
+		qdf_mem_free(ie);
+	}
+
+	/* Free vhtcap ie */
+	ie = req->scan_req.vhtcap.ptr;
+	if (ie) {
+		req->scan_req.vhtcap.len = 0;
+		req->scan_req.vhtcap.ptr = NULL;
+		qdf_mem_free(ie);
+	}
+	/* free scan_start_request memory */
+	qdf_mem_free(req);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+scm_scan_get_pdev_global_event_handlers(struct scan_event_listeners *listeners,
+		struct pdev_scan_ev_handler *pdev_ev_handler)
+{
+	uint32_t i;
+	struct cb_handler *cb_handlers  = &(pdev_ev_handler->cb_handlers[0]);
+
+	for (i = 0; i < MAX_SCAN_EVENT_HANDLERS_PER_PDEV; i++, cb_handlers++) {
+		if ((cb_handlers->func) &&
+		    (listeners->count < MAX_SCAN_EVENT_LISTENERS)) {
+			listeners->cb[listeners->count].func =
+				cb_handlers->func;
+			listeners->cb[listeners->count].arg =
+				cb_handlers->arg;
+			listeners->count++;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+scm_scan_get_requester_event_handler(struct scan_event_listeners *listeners,
+		struct scan_requester_info *requesters,
+		wlan_scan_requester requester_id)
+{
+	uint32_t idx = requester_id & ~WLAN_SCAN_REQUESTER_ID_PREFIX;
+	struct cb_handler *ev_handler = &(requesters[idx].ev_handler);
+
+	if (ev_handler->func) {
+		if (listeners->count < MAX_SCAN_EVENT_LISTENERS) {
+			listeners->cb[listeners->count].func = ev_handler->func;
+			listeners->cb[listeners->count].arg = ev_handler->arg;
+			listeners->count++;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void scm_scan_post_event(struct wlan_objmgr_vdev *vdev,
+		struct scan_event *event)
+{
+	uint32_t i = 0;
+	struct wlan_scan_obj *scan;
+	struct pdev_scan_ev_handler *pdev_ev_handler;
+	struct cb_handler *cb_handlers;
+	struct scan_requester_info *requesters;
+	struct scan_event_listeners *listeners;
+
+	if (!vdev || !event) {
+		scm_err("vdev: 0x%p, event: 0x%p", vdev, event);
+		return;
+	}
+	if (!event->requester) {
+		scm_err("invalid requester id");
+		QDF_ASSERT(0);
+	}
+	scm_info("vdev: 0x%p, event: 0x%p", vdev, event);
+
+	scan = wlan_vdev_get_scan_obj(vdev);
+	pdev_ev_handler = wlan_vdev_get_pdev_scan_ev_handlers(vdev);
+	cb_handlers = &(pdev_ev_handler->cb_handlers[0]);
+	requesters = scan->requesters;
+
+	scm_info("vdev: %d, type: %d, reason: %d, freq: %d, req: %d, scanid: %d",
+		event->vdev_id, event->type, event->reason, event->chan_freq,
+		event->requester, event->scan_id);
+
+	listeners = qdf_mem_malloc(sizeof(*listeners));
+	if (!listeners) {
+		scm_warn("couldn't allocate listeners list");
+		return;
+	}
+
+	/* initialize number of listeners */
+	listeners->count = 0;
+
+	/*
+	 * Initiator of scan request decides which all scan events
+	 * he is interested in and FW will send only those scan events
+	 * to host driver.
+	 * All the events received by scan module will be notified
+	 * to all registered handlers.
+	 */
+
+	qdf_spin_lock_bh(&scan->lock);
+	/* find all global scan event handlers on this pdev */
+	scm_scan_get_pdev_global_event_handlers(listeners, pdev_ev_handler);
+	/* find owner who triggered this scan request */
+	scm_scan_get_requester_event_handler(listeners, requesters,
+			event->requester);
+	qdf_spin_unlock_bh(&scan->lock);
+
+	/* notify all interested handlers */
+	for (i = 0; i < listeners->count; i++) {
+		scm_debug("func: 0x%p, arg: 0x%p",
+			listeners->cb[i].func, listeners->cb[i].arg);
+		listeners->cb[i].func(vdev, event, listeners->cb[i].arg);
+	}
+	qdf_mem_free(listeners);
+}
+
+static QDF_STATUS
+scm_release_serialization_command(struct wlan_objmgr_vdev *vdev,
+		uint32_t scan_id)
+{
+	struct wlan_serialization_queued_cmd_info cmd = {0};
+
+	cmd.requestor = WLAN_UMAC_COMP_SCAN;
+	cmd.cmd_type = WLAN_SER_CMD_SCAN;
+	cmd.cmd_id = scan_id;
+	cmd.req_type = WLAN_SER_CANCEL_SINGLE_SCAN;
+	cmd.vdev = vdev;
+	cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
+
+	/* Inform serialization for command completion */
+	wlan_serialization_remove_cmd(&cmd);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+scm_post_internal_scan_complete_event(struct scan_start_request *req,
+		enum scan_completion_reason reason)
+{
+	struct scan_event event = {0, };
+
+	/* prepare internal scan complete event */
+	event.type = SCAN_EVENT_TYPE_COMPLETED;
+	event.reason = reason;
+	event.chan_freq = 0; /* Invalid frequency */
+	event.vdev_id =  req->scan_req.vdev_id;
+	event.requester = req->scan_req.scan_req_id;
+	event.scan_id = req->scan_req.scan_id;
+
+	/* post scan event to registered handlers */
+	scm_scan_post_event(req->vdev, &event);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline struct pdev_scan_info *
+scm_scan_get_pdev_priv_info(uint8_t pdev_id, struct wlan_scan_obj *scan_obj)
+{
+	return &scan_obj->pdev_info[pdev_id];
+}
+
+static QDF_STATUS
+scm_update_last_scan_time(struct scan_start_request *req)
+{
+	uint8_t pdev_id;
+	struct wlan_scan_obj *scan_obj;
+	struct pdev_scan_info *pdev_scan_info;
+
+	scan_obj = wlan_vdev_get_scan_obj(req->vdev);
+	pdev_id = wlan_scan_vdev_get_pdev_id(req->vdev);
+	pdev_scan_info = scm_scan_get_pdev_priv_info(pdev_id, scan_obj);
+	/* update last scan start time */
+	pdev_scan_info->last_scan_time = qdf_system_ticks();
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+scm_activate_scan_request(struct scan_start_request *req)
+{
+	QDF_STATUS status;
+
+	status = tgt_scan_start(req);
+	if (status != QDF_STATUS_SUCCESS) {
+		scm_info("tgt_scan_start failed, status: %d", status);
+		/* scan could not be started and hence
+		 * we will not receive any completions.
+		 * post scan cancelled
+		 */
+		scm_post_internal_scan_complete_event(req,
+				SCAN_REASON_CANCELLED);
+		return status;
+	}
+	/* save last scan start time */
+	status = scm_update_last_scan_time(req);
+
+	return status;
+}
+
+static QDF_STATUS
+scm_cancel_scan_request(struct scan_start_request *req)
+{
+	struct scan_cancel_request cancel_req = {0, };
+	QDF_STATUS status;
+
+	cancel_req.vdev = req->vdev;
+	cancel_req.cancel_req.scan_id = req->scan_req.scan_id;
+	cancel_req.cancel_req.requester = req->scan_req.scan_req_id;
+	cancel_req.cancel_req.req_type = WLAN_SCAN_CANCEL_SINGLE;
+	cancel_req.cancel_req.vdev_id = req->scan_req.vdev_id;
+	/* send scan cancel to fw */
+	status = tgt_scan_cancel(&cancel_req);
+	if (status != QDF_STATUS_SUCCESS)
+		scm_err("tgt_scan_cancel failed: status: %d, scanid: %d",
+			status, req->scan_req.scan_id);
+	/* notify event handler about scan cancellation */
+	scm_post_internal_scan_complete_event(req, SCAN_REASON_CANCELLED);
+
+	return status;
+}
+
+static QDF_STATUS
+scm_scan_serialize_callback(struct wlan_serialization_command *cmd,
+	enum wlan_serialization_cb_reason reason)
+{
+	struct scan_start_request *req;
+	QDF_STATUS status;
+
+	if (!cmd || !cmd->umac_cmd) {
+		scm_err("cmd: %p, umac_cmd: %p, reason: %d",
+			cmd, cmd->umac_cmd, reason);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	req = cmd->umac_cmd;
+	scm_info("reason: %d, reqid:%d, scanid: %d, vdev_id: %d",
+		reason, req->scan_req.scan_req_id,
+		req->scan_req.scan_id, req->scan_req.vdev_id);
+
+	switch (reason) {
+	case WLAN_SER_CB_ACTIVATE_CMD:
+		/* command moved to active list
+		 * modify the params if required for concurency case.
+		 */
+		status = scm_activate_scan_request(req);
+		break;
+
+	case WLAN_SER_CB_CANCEL_CMD:
+		/* command removed from pending list.
+		 * notify registered scan event handlers with
+		 * status completed and reason cancelled.
+		 */
+		status = scm_post_internal_scan_complete_event(req,
+				SCAN_REASON_CANCELLED);
+		break;
+
+	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
+		/* active command timed out.
+		 * prepare internal scan cancel request
+		 */
+		status = scm_cancel_scan_request(req);
+		break;
+
+	case WLAN_SER_CB_RELEASE_MEM_CMD:
+		/* command successfully completed.
+		 * release scan_start_request memory
+		 */
+		status = scm_free_scan_request_mem(req);
+		break;
+
+	default:
+		/* Do nothing but logging */
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+}
+
+QDF_STATUS
+scm_scan_start_req(struct scheduler_msg *msg)
+{
+	struct wlan_serialization_command cmd = {0, };
+	enum wlan_serialization_status ser_cmd_status;
+	struct scan_start_request *req;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!msg || !msg->bodyptr) {
+		scm_err("msg: 0x%p, bodyptr: 0x%p", msg, msg->bodyptr);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	req = msg->bodyptr;
+	cmd.cmd_type = WLAN_SER_CMD_SCAN;
+	cmd.cmd_id = req->scan_req.scan_id;
+	cmd.cmd_cb = (wlan_serialization_cmd_callback)
+		scm_scan_serialize_callback;
+	cmd.umac_cmd = req;
+	cmd.source = WLAN_UMAC_COMP_SCAN;
+	cmd.is_high_priority = false;
+	cmd.cmd_timeout_duration = req->scan_req.max_scan_time +
+		SCAN_TIMEOUT_GRACE_PERIOD;
+	cmd.vdev = req->vdev;
+
+	scm_info("req: 0x%p, reqid: %d, scanid: %d, vdevid: %d",
+		req, req->scan_req.scan_req_id, req->scan_req.scan_id,
+		req->scan_req.vdev_id);
+
+	ser_cmd_status = wlan_serialization_request(&cmd);
+	scm_info("wlan_serialization_request status:%d", ser_cmd_status);
+
+	switch (ser_cmd_status) {
+	case WLAN_SER_CMD_PENDING:
+		/* command moved to pending list.Do nothing */
+		break;
+	case WLAN_SER_CMD_ACTIVE:
+		/* command moved to active list. Do nothing */
+		break;
+	case WLAN_SER_CMD_DENIED_LIST_FULL:
+	case WLAN_SER_CMD_DENIED_RULES_FAILED:
+	case WLAN_SER_CMD_DENIED_UNSPECIFIED:
+		/* notify registered scan event handlers
+		 * about internal error
+		 */
+		scm_post_internal_scan_complete_event(req,
+				SCAN_REASON_INTERNAL_FAILURE);
+		/* cmd can't be serviced.
+		 * release scan_start_request memory.
+		 */
+		scm_free_scan_request_mem(req);
+		break;
+	default:
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+}
+
+static inline enum wlan_serialization_cancel_type
+get_serialization_cancel_type(enum scan_cancel_req_type type)
+{
+	enum wlan_serialization_cancel_type serialization_type;
+
+	switch (type) {
+	case WLAN_SCAN_CANCEL_SINGLE:
+		serialization_type = WLAN_SER_CANCEL_SINGLE_SCAN;
+		break;
+	case WLAN_SCAN_CANCEL_VDEV_ALL:
+		serialization_type = WLAN_SER_CANCEL_VDEV_SCANS;
+		break;
+	case WLAN_SCAN_CANCEL_PDEV_ALL:
+		serialization_type = WLAN_SER_CANCEL_PDEV_SCANS;
+		break;
+	default:
+		QDF_ASSERT(0);
+		scm_warn("invalid scan_cancel_req_type: %d", type);
+		serialization_type = WLAN_SER_CANCEL_PDEV_SCANS;
+		break;
+	}
+
+	return serialization_type;
+}
+
+QDF_STATUS
+scm_scan_cancel_req(struct scheduler_msg *msg)
+{
+	struct wlan_serialization_queued_cmd_info cmd = {0,};
+	enum wlan_serialization_cmd_status ser_cmd_status;
+	struct scan_cancel_request *req;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!msg || !msg->bodyptr) {
+		scm_err("msg: 0x%p, bodyptr: 0x%p", msg, msg->bodyptr);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	req = msg->bodyptr;
+	cmd.requestor = 0;
+	cmd.cmd_type = WLAN_SER_CMD_SCAN;
+	cmd.cmd_id = req->cancel_req.scan_id;
+	cmd.vdev = req->vdev;
+	cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE |
+		WLAN_SERIALIZATION_PENDING_QUEUE;
+	cmd.req_type = get_serialization_cancel_type(req->cancel_req.req_type);
+
+	ser_cmd_status = wlan_serialization_cancel_request(&cmd);
+
+	scm_info("status: %d, reqid: %d, scanid: %d, vdevid: %d, type: %d",
+		ser_cmd_status, req->cancel_req.requester,
+		req->cancel_req.scan_id, req->cancel_req.vdev_id,
+		req->cancel_req.req_type);
+
+	switch (ser_cmd_status) {
+	case WLAN_SER_CMD_IN_PENDING_LIST:
+		/* do nothing */
+		break;
+	case WLAN_SER_CMD_IN_ACTIVE_LIST:
+	case WLAN_SER_CMDS_IN_ALL_LISTS:
+		/* send wmi scan cancel to fw */
+		status = tgt_scan_cancel(req);
+		break;
+	case WLAN_SER_CMD_NOT_FOUND:
+		/* do nothing */
+		break;
+	default:
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+	/* Free cancel request memory */
+	qdf_mem_free(req);
+
+	return status;
+}
+
+QDF_STATUS
+scm_scan_event_handler(struct scheduler_msg *msg)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct scan_event *event;
+	struct scan_event_info *event_info;
+
+	if (!msg || !msg->bodyptr) {
+		scm_err("msg: %p, bodyptr: %p", msg, msg->bodyptr);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	event_info = msg->bodyptr;
+	vdev = event_info->vdev;
+	event = &(event_info->event);
+
+	scm_info("vdev: %d, type: %d, reason: %d, freq: %d, req: %d, scanid: %d",
+		event->vdev_id, event->type, event->reason, event->chan_freq,
+		event->requester, event->scan_id);
+
+	switch (event->type) {
+	case SCAN_EVENT_TYPE_COMPLETED:
+	case SCAN_EVENT_TYPE_START_FAILED:
+	case SCAN_EVENT_TYPE_DEQUEUED:
+		scm_release_serialization_command(vdev, event->scan_id);
+		break;
+	default:
+		break;
+	}
+
+	/* Notify all interested parties */
+	scm_scan_post_event(vdev, event);
+	/* free event info memory */
+	qdf_mem_free(event_info);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_SCAN_ID);
+
+	return QDF_STATUS_SUCCESS;
+}

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

@@ -23,11 +23,11 @@
 #ifndef _WLAN_SCAN_TGT_API_H_
 #define _WLAN_SCAN_TGT_API_H_
 
-#include <wlan_scan_structs.h>
 #include <wlan_objmgr_psoc_obj.h>
 #include <wlan_objmgr_pdev_obj.h>
 #include <wlan_objmgr_vdev_obj.h>
 #include <wlan_objmgr_peer_obj.h>
+#include <wlan_scan_public_structs.h>
 #include <wlan_mgmt_txrx_utils_api.h>
 
 /**

+ 1 - 1
umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h

@@ -24,10 +24,10 @@
 #define _WLAN_SCAN_UCFG_API_H_
 
 #include <scheduler_api.h>
-#include <wlan_scan_public_structs.h>
 #include <wlan_objmgr_psoc_obj.h>
 #include <wlan_objmgr_pdev_obj.h>
 #include <wlan_objmgr_vdev_obj.h>
+#include <wlan_scan_public_structs.h>
 
 /**
  * ucfg_scan_register_requester() - assigns requester ID to caller and

+ 3 - 0
umac/scan/dispatcher/inc/wlan_scan_utils_api.h

@@ -25,6 +25,9 @@
 
 #include <wlan_objmgr_cmn.h>
 #include <qdf_mc_timer.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
 #include <wlan_scan_public_structs.h>
 #include<wlan_mgmt_txrx_utils_api.h>
 

+ 156 - 0
umac/scan/dispatcher/src/wlan_scan_tgt_api.c

@@ -19,3 +19,159 @@
 /*
  * DOC: contains scan south bound interface definitions
  */
+
+#include <wlan_scan_ucfg_api.h>
+#include <wlan_scan_tgt_api.h>
+#include <wlan_objmgr_cmn.h>
+#include <wlan_lmac_if_def.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <../../core/src/wlan_scan_manager.h>
+
+static inline struct wlan_lmac_if_scan_tx_ops *
+wlan_psoc_get_scan_txops(struct wlan_objmgr_psoc *psoc)
+{
+	return &((psoc->soc_cb.tx_ops.scan));
+}
+
+static inline struct wlan_lmac_if_scan_tx_ops *
+wlan_vdev_get_scan_txops(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_psoc *psoc = NULL;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+
+	return wlan_psoc_get_scan_txops(psoc);
+}
+
+static inline struct wlan_lmac_if_scan_rx_ops *
+wlan_vdev_get_scan_rxops(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_psoc *psoc = NULL;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+
+	return &((psoc->soc_cb.rx_ops.scan));
+}
+
+QDF_STATUS
+tgt_scan_nlo_complete_evt_handler(void *handle, uint8_t *event,
+	uint32_t len)
+{
+	/*
+	 * Convert the tlv/non tlv data to struct scan_event
+	 * (SCM_EVENT_NLO_COMPLETE) (same as WIN does by calling a win API) and
+	 * Post msg to target_if queue
+	 */
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+tgt_nlo_match_evt_handler(void *handle, uint8_t *event,
+		uint32_t len)
+{
+	/*
+	 * Convert the tlv/non tlv data to comman data
+	 * and set the pno match received flag in vdev scan info
+	 */
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+tgt_scan_start(struct scan_start_request *req)
+{
+	struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL;
+	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(req->vdev);
+
+	scan_ops = wlan_vdev_get_scan_txops(req->vdev);
+	/* invoke wmi_unified_scan_start_cmd_send() */
+	QDF_ASSERT(scan_ops->scan_start);
+	if (scan_ops->scan_start)
+		return scan_ops->scan_start(psoc, req);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+
+QDF_STATUS
+tgt_scan_cancel(struct scan_cancel_request *req)
+{
+	struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL;
+	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(req->vdev);
+
+	scan_ops = wlan_vdev_get_scan_txops(req->vdev);
+	/* invoke wmi_unified_scan_stop_cmd_send() */
+	QDF_ASSERT(scan_ops->scan_cancel);
+	if (scan_ops->scan_cancel)
+		return scan_ops->scan_cancel(psoc, &(req->cancel_req));
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+tgt_scan_register_ev_handler(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL;
+
+	scan_ops = wlan_psoc_get_scan_txops(psoc);
+	/* invoke wmi_unified_register_event_handler()
+	 * since event id, handler function and context is
+	 * already known to offload lmac, passing NULL as argument.
+	 * DA can pass necessary arguments by clubing then into
+	 * some structure.
+	 */
+	QDF_ASSERT(scan_ops->scan_reg_ev_handler);
+	if (scan_ops->scan_reg_ev_handler)
+		return scan_ops->scan_reg_ev_handler(psoc, NULL);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+tgt_scan_unregister_ev_handler(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL;
+
+	scan_ops = wlan_psoc_get_scan_txops(psoc);
+	/* invoke wmi_unified_register_event_handler()
+	 * since event id, handler function and context is
+	 * already known to offload lmac, passing NULL as argument.
+	 * DA can pass necessary arguments by clubing then into
+	 * some structure.
+	 */
+	QDF_ASSERT(scan_ops->scan_unreg_ev_handler);
+	if (scan_ops->scan_unreg_ev_handler)
+		return scan_ops->scan_unreg_ev_handler(psoc, NULL);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+tgt_scan_event_handler(struct wlan_objmgr_psoc *psoc,
+		struct scan_event_info *event_info)
+{
+	struct scheduler_msg msg = {0,};
+	struct scan_event *event = &event_info->event;
+	uint8_t vdev_id = event->vdev_id;
+
+	if (!psoc || !event_info) {
+		scm_err("psoc: 0x%p, event_info: 0x%p", psoc, event_info);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	scm_info("vdev: %d, type: %d, reason: %d, freq: %d, req: %d, scanid: %d",
+		vdev_id, event->type, event->reason, event->chan_freq,
+		event->requester, event->scan_id);
+
+	event_info->vdev =
+		wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+				vdev_id, WLAN_SCAN_ID);
+	if (!event_info->vdev) {
+		scm_err("null vdev, vdev_id: %d, psoc: 0x%p", vdev_id, psoc);
+		return QDF_STATUS_E_INVAL;
+	}
+	msg.bodyptr = event_info;
+	msg.callback = scm_scan_event_handler;
+
+	return scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg);
+}

+ 544 - 15
umac/scan/dispatcher/src/wlan_scan_ucfg_api.c

@@ -20,11 +20,15 @@
  * DOC: contains scan north bound interface definitions
  */
 
-#include <wlan_cmn.h>
-#include <wlan_scan_utils_api.h>
+#include <scheduler_api.h>
 #include <wlan_scan_ucfg_api.h>
-#include "../../core/src/wlan_scan_main.h"
 #include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_cmn.h>
+#include <wlan_serialization_api.h>
+#include <wlan_scan_tgt_api.h>
+#include "../../core/src/wlan_scan_main.h"
+#include "../../core/src/wlan_scan_manager.h"
+#include "../../core/src/wlan_scan_cache_db.h"
 
 QDF_STATUS ucfg_scan_init(void)
 {
@@ -53,7 +57,7 @@ fail_create_psoc:
 
 QDF_STATUS ucfg_scan_deinit(void)
 {
-	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	QDF_STATUS status;
 
 	status = wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_SCAN,
 		wlan_scan_psoc_created_notification, NULL);
@@ -69,9 +73,222 @@ QDF_STATUS ucfg_scan_deinit(void)
 	return status;
 }
 
-static QDF_STATUS wlan_scan_global_init(struct wlan_scan_obj *scan_obj)
+QDF_STATUS
+ucfg_scan_start(struct scan_start_request *req)
+{
+	struct scheduler_msg msg = {0, };
+
+	if (!req || !req->vdev) {
+		scm_err("vdev: %p, req: %p", req->vdev, req);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	scm_info("reqid: %d, scanid: %d, vdevid: %d",
+		req->scan_req.scan_req_id, req->scan_req.scan_id,
+		req->scan_req.vdev_id);
+	msg.bodyptr = req;
+	msg.callback = scm_scan_start_req;
+
+	return scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+}
+
+QDF_STATUS
+ucfg_scan_cancel(struct scan_cancel_request *req)
+{
+	struct scheduler_msg msg = {0, };
+
+	if (!req || !req->vdev) {
+		scm_err("vdev: %p, req: %p", req->vdev, req);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	scm_info("reqid: %d, scanid: %d, vdevid: %d, type: %d",
+		req->cancel_req.requester, req->cancel_req.scan_id,
+		req->cancel_req.vdev_id, req->cancel_req.req_type);
+	msg.bodyptr = req;
+	msg.callback = scm_scan_cancel_req;
+
+	return scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+}
+
+wlan_scan_requester
+ucfg_scan_register_requester(struct wlan_objmgr_psoc *psoc,
+	uint8_t *name, scan_event_handler event_cb, void *arg)
+{
+	int i, j;
+	struct wlan_scan_obj *scan;
+	struct scan_requester_info *requesters;
+	wlan_scan_requester requester = {0};
+
+	if (!psoc) {
+		scm_err("null psoc");
+		return 0;
+	}
+	scan = wlan_psoc_get_scan_obj(psoc);
+	requesters = scan->requesters;
+	qdf_spin_lock_bh(&scan->lock);
+	for (i = 0; i < WLAN_MAX_REQUESTORS; ++i) {
+		if (requesters[i].requester == 0) {
+			requesters[i].requester =
+				WLAN_SCAN_REQUESTER_ID_PREFIX | i;
+			j = 0;
+			while (name[j] && (j < (WLAN_MAX_MODULE_NAME - 1))) {
+				requesters[i].module[j] = name[j];
+				++j;
+			}
+			requesters[i].module[j] = 0;
+			requesters[i].ev_handler.func = event_cb;
+			requesters[i].ev_handler.arg = arg;
+			requester = requesters[i].requester;
+			break;
+		}
+	}
+	qdf_spin_unlock_bh(&scan->lock);
+	scm_info("module: %s, event_cb: 0x%p, arg: 0x%p, reqid: %d",
+		name, event_cb, arg, requester);
+
+	return requester;
+}
+
+void
+ucfg_scan_unregister_requester(struct wlan_objmgr_psoc *psoc,
+	wlan_scan_requester requester)
 {
+	int idx = requester & ~WLAN_SCAN_REQUESTER_ID_PREFIX;
+	struct wlan_scan_obj *scan;
+	struct scan_requester_info *requesters;
+
+	if (!psoc) {
+		scm_err("null psoc");
+		return;
+	}
+	scan = wlan_psoc_get_scan_obj(psoc);
+	requesters = scan->requesters;
+	scm_info("reqid: %d", requester);
+
+	qdf_spin_lock_bh(&scan->lock);
+	requesters[idx].requester = 0;
+	requesters[idx].module[0] = 0;
+	requesters[idx].ev_handler.func = NULL;
+	requesters[idx].ev_handler.arg = NULL;
+	qdf_spin_unlock_bh(&scan->lock);
+}
+
+uint8_t*
+ucfg_get_scan_requester_name(struct wlan_objmgr_psoc *psoc,
+	wlan_scan_requester requester)
+{
+	int idx = requester & ~WLAN_SCAN_REQUESTER_ID_PREFIX;
+	struct wlan_scan_obj *scan;
+	struct scan_requester_info *requesters;
+
+	if (!psoc) {
+		scm_err("null psoc");
+		return "null";
+	}
+	scan = wlan_psoc_get_scan_obj(psoc);
+	requesters = scan->requesters;
+
+	if ((idx < WLAN_MAX_REQUESTORS) &&
+		(requesters[idx].requester == requester)) {
+		return requesters[idx].module;
+	}
 
+	return (uint8_t *)"unknown";
+}
+
+wlan_scan_id
+ucfg_scan_get_scan_id(struct wlan_objmgr_psoc *psoc)
+{
+	wlan_scan_id id;
+	struct wlan_scan_obj *scan;
+
+	if (!psoc) {
+		QDF_ASSERT(0);
+		scm_err("null psoc");
+		return 0;
+	}
+	scan = wlan_psoc_get_scan_obj(psoc);
+
+	id = qdf_atomic_inc_return(&scan->scan_ids);
+	id =  id & WLAN_SCAN_ID_MASK;
+	/* Mark this scan request as triggered by host
+	 * by setting WLAN_HOST_SCAN_REQ_ID_PREFIX flag.
+	 */
+	id =  id | WLAN_HOST_SCAN_REQ_ID_PREFIX;
+	scm_info("scan_id: 0x%x", id);
+
+	return id;
+}
+
+static QDF_STATUS
+scm_add_scan_event_handler(struct pdev_scan_ev_handler *pdev_ev_handler,
+	scan_event_handler event_cb, void *arg)
+{
+	struct cb_handler *cb_handler;
+	uint32_t handler_cnt = pdev_ev_handler->handler_cnt;
+
+	/* Assign next available slot to this registration request */
+	cb_handler = &(pdev_ev_handler->cb_handlers[handler_cnt]);
+	cb_handler->func = event_cb;
+	cb_handler->arg = arg;
+	pdev_ev_handler->handler_cnt++;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_scan_register_event_handler(struct wlan_objmgr_vdev *vdev,
+	scan_event_handler event_cb, void *arg)
+{
+	uint32_t idx;
+	struct wlan_scan_obj *scan;
+	struct pdev_scan_ev_handler *pdev_ev_handler;
+	struct cb_handler *cb_handler;
+
+	/* scan event handler call back can't be NULL */
+	if (!vdev || !event_cb) {
+		scm_err("vdev: %p, event_cb: %p", vdev, event_cb);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	scm_info("vdev: %p, event_cb: %p, arg: %p\n", vdev, event_cb, arg);
+
+	scan = wlan_vdev_get_scan_obj(vdev);
+	pdev_ev_handler = wlan_vdev_get_pdev_scan_ev_handlers(vdev);
+	cb_handler = &(pdev_ev_handler->cb_handlers[0]);
+
+	qdf_spin_lock_bh(&scan->lock);
+	/* Ensure its not a duplicate registration request */
+	for (idx = 0; idx < MAX_SCAN_EVENT_HANDLERS_PER_PDEV;
+		idx++, cb_handler++) {
+		if ((cb_handler->func == event_cb) &&
+			(cb_handler->arg == arg)) {
+			qdf_spin_unlock_bh(&scan->lock);
+			scm_warn("func: %p, arg: %p already exists",
+				event_cb, arg);
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+
+	QDF_ASSERT(pdev_ev_handler->handler_cnt <
+			MAX_SCAN_EVENT_HANDLERS_PER_PDEV);
+
+	if (pdev_ev_handler->handler_cnt >= MAX_SCAN_EVENT_HANDLERS_PER_PDEV) {
+		qdf_spin_unlock_bh(&scan->lock);
+		scm_warn("No more registrations possible");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	scm_add_scan_event_handler(pdev_ev_handler, event_cb, arg);
+	qdf_spin_unlock_bh(&scan->lock);
+
+	scm_info("event_cb: 0x%p, arg: 0x%p", event_cb, arg);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+wlan_scan_global_init(struct wlan_scan_obj *scan_obj)
+{
 	scan_obj->scan_def.active_dwell = SCAN_ACTIVE_DWELL_TIME;
 	scan_obj->scan_def.passive_dwell = SCAN_PASSIVE_DWELL_TIME;
 	scan_obj->scan_def.max_rest_time = SCAN_MAX_REST_TIME;
@@ -102,28 +319,301 @@ static QDF_STATUS wlan_scan_global_init(struct wlan_scan_obj *scan_obj)
 	scan_obj->scan_def.scan_ev_bss_chan = true;
 	scan_obj->scan_def.scan_ev_foreign_chan = true;
 	scan_obj->scan_def.scan_ev_dequeued = true;
-
+	/* init scan id seed */
 	qdf_atomic_init(&scan_obj->scan_ids);
 
 	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS ucfg_scan_psoc_enable(struct wlan_objmgr_psoc *psoc)
+static QDF_STATUS
+scm_remove_scan_event_handler(struct pdev_scan_ev_handler *pdev_ev_handler,
+	struct cb_handler *entry)
+{
+	struct cb_handler *last_entry;
+	uint32_t handler_cnt = pdev_ev_handler->handler_cnt;
+
+	/* Replace event handler being deleted
+	 * with the last one in the list.
+	 */
+	last_entry = &(pdev_ev_handler->cb_handlers[handler_cnt - 1]);
+	entry->func = last_entry->func;
+	entry->arg = last_entry->arg;
+
+	/* Clear our last entry */
+	last_entry->func = NULL;
+	last_entry->arg = NULL;
+	pdev_ev_handler->handler_cnt--;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void
+ucfg_scan_unregister_event_handler(struct wlan_objmgr_vdev *vdev,
+	scan_event_handler event_cb, void *arg)
+{
+	uint8_t found = false;
+	uint32_t idx;
+	uint32_t handler_cnt;
+	struct wlan_scan_obj *scan;
+	struct cb_handler *cb_handler;
+	struct pdev_scan_ev_handler *pdev_ev_handler;
+
+	scm_info("vdev: %p, event_cb: 0x%p, arg: 0x%p", vdev, event_cb, arg);
+	if (!vdev) {
+		scm_err("null vdev");
+		return;
+	}
+	scan = wlan_vdev_get_scan_obj(vdev);
+	pdev_ev_handler = wlan_vdev_get_pdev_scan_ev_handlers(vdev);
+	cb_handler = &(pdev_ev_handler->cb_handlers[0]);
+
+	qdf_spin_lock_bh(&scan->lock);
+	handler_cnt = pdev_ev_handler->handler_cnt;
+	if (!handler_cnt) {
+		qdf_spin_unlock_bh(&scan->lock);
+		scm_info("No event handlers registered");
+	}
+
+	for (idx = 0; idx < MAX_SCAN_EVENT_HANDLERS_PER_PDEV;
+		idx++, cb_handler++) {
+		if ((cb_handler->func == event_cb) &&
+			(cb_handler->arg == arg)) {
+			/* Event handler found, remove it
+			 * from event handler list.
+			 */
+			found = true;
+			scm_remove_scan_event_handler(pdev_ev_handler,
+				cb_handler);
+			handler_cnt--;
+			break;
+		}
+	}
+	qdf_spin_unlock_bh(&scan->lock);
+
+	scm_info("event handler %s, remaining handlers: %d",
+		(found ? "removed" : "not found"), handler_cnt);
+}
+
+QDF_STATUS
+ucfg_scan_init_default_params(struct wlan_objmgr_vdev *vdev,
+	struct scan_start_request *req)
+{
+	struct scan_default_params *def;
+
+	if (!vdev | !req) {
+		scm_err("vdev: 0x%p, req: 0x%p", vdev, req);
+		return QDF_STATUS_E_INVAL;
+	}
+	def = wlan_vdev_get_def_scan_params(vdev);
+
+	/* Zero out everything and explicitly set fields as required */
+	qdf_mem_zero(req, sizeof(*req));
+
+	req->vdev = vdev;
+	req->scan_req.vdev_id = wlan_vdev_get_id(vdev);
+	req->scan_req.scan_priority = def->scan_priority;
+	req->scan_req.dwell_time_active = def->active_dwell;
+	req->scan_req.dwell_time_passive = def->passive_dwell;
+	req->scan_req.min_rest_time = def->min_rest_time;
+	req->scan_req.max_rest_time = def->max_rest_time;
+	req->scan_req.repeat_probe_time = def->repeat_probe_time;
+	req->scan_req.probe_spacing_time = def->probe_spacing_time;
+	req->scan_req.idle_time = def->idle_time;
+	req->scan_req.max_scan_time = def->max_scan_time;
+	req->scan_req.probe_delay = def->probe_delay;
+	req->scan_req.burst_duration = def->burst_duration;
+	req->scan_req.n_probes = def->num_probes;
+	req->scan_req.scan_flags = def->scan_flags;
+	req->scan_req.scan_events = def->scan_events;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_scan_init_ssid_params(struct scan_start_request *req,
+		uint32_t num_ssid, struct wlan_ssid *ssid_list)
 {
+	uint32_t max_ssid = sizeof(req->scan_req.ssid) /
+				sizeof(req->scan_req.ssid[0]);
+
+	if (!req) {
+		scm_err("null request");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	if (!num_ssid) {
+		/* empty channel list provided */
+		req->scan_req.num_ssids = 0;
+		qdf_mem_zero(&req->scan_req.ssid[0],
+			sizeof(req->scan_req.ssid));
+		return QDF_STATUS_SUCCESS;
+	}
+	if (!ssid_list) {
+		scm_err("null ssid_list while num_ssid: %d", num_ssid);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	if (num_ssid > max_ssid) {
+		/* got a big list. alert and continue */
+		scm_warn("overflow: received %d, max supported : %d",
+			num_ssid, max_ssid);
+		return QDF_STATUS_E_E2BIG;
+	}
+
+	if (max_ssid > num_ssid)
+		max_ssid = num_ssid;
+
+	req->scan_req.num_ssids = max_ssid;
+	qdf_mem_copy(&req->scan_req.ssid[0], ssid_list,
+		(req->scan_req.num_ssids * sizeof(req->scan_req.ssid[0])));
+
 	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS ucfg_scan_psoc_disable(struct wlan_objmgr_psoc *psoc)
+QDF_STATUS
+ucfg_scan_init_bssid_params(struct scan_start_request *req,
+		uint32_t num_bssid, struct qdf_mac_addr *bssid_list)
 {
+	uint32_t max_bssid = sizeof(req->scan_req.bssid_list) /
+				sizeof(req->scan_req.bssid_list[0]);
+
+	if (!req) {
+		scm_err("null request");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	if (!num_bssid) {
+		/* empty channel list provided */
+		req->scan_req.num_bssid = 0;
+		qdf_mem_zero(&req->scan_req.bssid_list[0],
+			sizeof(req->scan_req.bssid_list));
+		return QDF_STATUS_SUCCESS;
+	}
+	if (!bssid_list) {
+		scm_err("null bssid_list while num_bssid: %d", num_bssid);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	if (num_bssid > max_bssid) {
+		/* got a big list. alert and continue */
+		scm_warn("overflow: received %d, max supported : %d",
+			num_bssid, max_bssid);
+		return QDF_STATUS_E_E2BIG;
+	}
+
+	if (max_bssid > num_bssid)
+		max_bssid = num_bssid;
+
+	req->scan_req.num_bssid = max_bssid;
+	qdf_mem_copy(&req->scan_req.bssid_list[0], bssid_list,
+		req->scan_req.num_bssid * sizeof(req->scan_req.bssid_list[0]));
+
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS
+ucfg_scan_init_chanlist_params(struct scan_start_request *req,
+		uint32_t num_chans, uint32_t *chan_list)
+{
+
+	uint32_t max_chans = sizeof(req->scan_req.chan_list) /
+				sizeof(req->scan_req.chan_list[0]);
+	if (!req) {
+		scm_err("null request");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	if (!num_chans) {
+		/* empty channel list provided */
+		req->scan_req.num_chan = 0;
+		qdf_mem_zero(&req->scan_req.chan_list[0],
+			sizeof(req->scan_req.chan_list));
+		return QDF_STATUS_SUCCESS;
+	}
+	if (!chan_list) {
+		scm_err("null chan_list while num_chans: %d", num_chans);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
 
-QDF_STATUS ucfg_scan_psoc_open(struct wlan_objmgr_psoc *psoc)
+	if (num_chans > max_chans) {
+		/* got a big list. alert and continue */
+		scm_warn("overflow: received %d, max supported : %d",
+			num_chans, max_chans);
+		return QDF_STATUS_E_E2BIG;
+	}
+
+	if (max_chans > num_chans)
+		max_chans = num_chans;
+
+	req->scan_req.num_chan = max_chans;
+	qdf_mem_copy(&req->scan_req.chan_list[0], chan_list,
+		req->scan_req.num_chan * sizeof(req->scan_req.chan_list[0]));
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline enum scm_scan_status
+get_scan_status_from_serialization_status(
+	enum wlan_serialization_cmd_status status)
+{
+	enum scm_scan_status scan_status;
+
+	switch (status) {
+	case WLAN_SER_CMD_IN_PENDING_LIST:
+		scan_status = SCAN_IS_PENDING;
+		break;
+	case WLAN_SER_CMD_IN_ACTIVE_LIST:
+		scan_status = SCAN_IS_ACTIVE;
+		break;
+	case WLAN_SER_CMDS_IN_ALL_LISTS:
+		scan_status = SCAN_IS_ACTIVE_AND_PENDING;
+		break;
+	case WLAN_SER_CMD_NOT_FOUND:
+		scan_status = SCAN_NOT_IN_PROGRESS;
+		break;
+	default:
+		scm_warn("invalid serialization status %d", status);
+		QDF_ASSERT(0);
+		scan_status = SCAN_NOT_IN_PROGRESS;
+		break;
+	}
+
+	return scan_status;
+}
+
+enum scm_scan_status
+ucfg_scan_get_vdev_status(struct wlan_objmgr_vdev *vdev)
+{
+	enum wlan_serialization_cmd_status status;
+
+	if (!vdev) {
+		scm_err("null vdev");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	status = wlan_serialization_vdev_scan_status(vdev);
+
+	return get_scan_status_from_serialization_status(status);
+}
+
+enum scm_scan_status
+ucfg_scan_get_pdev_status(struct wlan_objmgr_pdev *pdev)
+{
+	enum wlan_serialization_cmd_status status;
+
+	if (!pdev) {
+		scm_err("null pdev");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	status = wlan_serialization_pdev_scan_status(pdev);
+
+	return get_scan_status_from_serialization_status(status);
+}
+
+QDF_STATUS
+ucfg_scan_psoc_open(struct wlan_objmgr_psoc *psoc)
 {
-	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct wlan_scan_obj *scan_obj;
 
+	scm_info("psoc open: 0x%p", psoc);
+	if (!psoc) {
+		scm_err("null psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
 	scan_obj = wlan_psoc_get_scan_obj(psoc);
 	if (scan_obj == NULL) {
 		scm_err("Failed to get scan object");
@@ -131,24 +621,63 @@ QDF_STATUS ucfg_scan_psoc_open(struct wlan_objmgr_psoc *psoc)
 	}
 	/* Initialize the scan Globals */
 	wlan_scan_global_init(scan_obj);
-
+	qdf_spinlock_create(&scan_obj->lock);
 	scm_db_init(psoc);
 
-	return status;
+	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS ucfg_scan_psoc_close(struct wlan_objmgr_psoc *psoc)
+QDF_STATUS
+ucfg_scan_psoc_close(struct wlan_objmgr_psoc *psoc)
 {
-	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct wlan_scan_obj *scan_obj;
 
+	scm_info("psoc close: 0x%p", psoc);
+	if (!psoc) {
+		scm_err("null psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
 	scan_obj = wlan_psoc_get_scan_obj(psoc);
 	if (scan_obj == NULL) {
 		scm_err("Failed to get scan object");
 		return QDF_STATUS_E_FAILURE;
 	}
-
+	qdf_spinlock_destroy(&scan_obj->lock);
 	scm_db_deinit(psoc);
 
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_scan_psoc_enable(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+
+	scm_info("psoc enable: 0x%p", psoc);
+	if (!psoc) {
+		scm_err("null psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
+	/* Subscribe for scan events from lmac layesr */
+	status = tgt_scan_register_ev_handler(psoc);
+	QDF_ASSERT(status == QDF_STATUS_SUCCESS);
+
+	return status;
+}
+
+QDF_STATUS
+ucfg_scan_psoc_disable(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+
+	scm_info("psoc disable: 0x%p", psoc);
+	if (!psoc) {
+		scm_err("null psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
+	/* Unsubscribe for scan events from lmac layesr */
+	status = tgt_scan_unregister_ev_handler(psoc);
+	QDF_ASSERT(status == QDF_STATUS_SUCCESS);
+
 	return status;
 }

+ 84 - 0
umac/scan/dispatcher/src/wlan_scan_utils_api.c

@@ -19,3 +19,87 @@
 /*
  * DOC: Defines scan utility functions
  */
+
+#include <wlan_scan_ucfg_api.h>
+#include <wlan_scan_utils_api.h>
+#include <../../core/src/wlan_scan_cache_db.h>
+#include <../../core/src/wlan_scan_main.h>
+
+const char*
+util_scan_get_ev_type_name(enum scan_event_type type)
+{
+	static const char * const event_name[] = {
+		[SCAN_EVENT_TYPE_STARTED] = "STARTED",
+		[SCAN_EVENT_TYPE_COMPLETED] = "COMPLETED",
+		[SCAN_EVENT_TYPE_BSS_CHANNEL] = "HOME_CHANNEL",
+		[SCAN_EVENT_TYPE_FOREIGN_CHANNEL] = "FOREIGN_CHANNEL",
+		[SCAN_EVENT_TYPE_DEQUEUED] = "DEQUEUED",
+		[SCAN_EVENT_TYPE_PREEMPTED] = "PREEMPTED",
+		[SCAN_EVENT_TYPE_START_FAILED] = "START_FAILED",
+		[SCAN_EVENT_TYPE_RESTARTED] = "RESTARTED",
+		[SCAN_EVENT_TYPE_FOREIGN_CHANNEL_EXIT] = "FOREIGN_CHANNEL_EXIT",
+		[SCAN_EVENT_TYPE_SUSPENDED] = "SUSPENDED",
+		[SCAN_EVENT_TYPE_RESUMED] = "RESUMED",
+		[SCAN_EVENT_TYPE_NLO_COMPLETE] = "NLO_COMPLETE",
+		[SCAN_EVENT_TYPE_INVALID] = "INVALID",
+		[SCAN_EVENT_TYPE_GPIO_TIMEOUT] = "GPIO_TIMEOUT",
+		[SCAN_EVENT_TYPE_RADIO_MEASUREMENT_START] =
+			"RADIO_MEASUREMENT_START",
+		[SCAN_EVENT_TYPE_RADIO_MEASUREMENT_END] =
+			"RADIO_MEASUREMENT_END",
+		[SCAN_EVENT_TYPE_BSSID_MATCH] = "BSSID_MATCH",
+		[SCAN_EVENT_TYPE_FOREIGN_CHANNEL_GET_NF] =
+			"FOREIGN_CHANNEL_GET_NF",
+	};
+
+	if (type >= SCAN_EVENT_TYPE_MAX) {
+		scm_err("unknown type : %d", type);
+		QDF_ASSERT(0);
+		return "UNKNOWN";
+	}
+
+	return event_name[type];
+}
+
+
+const char*
+util_scan_get_ev_reason_name(enum scan_completion_reason reason)
+{
+	static const char * const reason_name[] = {
+		[SCAN_REASON_NONE] = "NONE",
+		[SCAN_REASON_COMPLETED] = "COMPLETED",
+		[SCAN_REASON_CANCELLED] = "CANCELLED",
+		[SCAN_REASON_PREEMPTED] = "PREEMPTED",
+		[SCAN_REASON_TIMEDOUT] = "TIMEDOUT",
+		[SCAN_REASON_INTERNAL_FAILURE] = "INTERNAL_FAILURE",
+		[SCAN_REASON_SUSPENDED] = "SUSPENDED",
+		[SCAN_REASON_RUN_FAILED] = "RUN_FAILED",
+		[SCAN_REASON_TERMINATION_FUNCTION] = "TERMINATION_FUNCTION",
+		[SCAN_REASON_MAX_OFFCHAN_RETRIES] = "MAX_OFFCHAN_RETRIES",
+	};
+
+	if (reason >= SCAN_REASON_MAX) {
+		scm_err("unknown reason : %d", reason);
+		QDF_ASSERT(0);
+		return "UNKNOWN";
+	}
+
+	return reason_name[reason];
+}
+
+qdf_time_t
+util_get_last_scan_time(struct wlan_objmgr_vdev *vdev)
+{
+	uint8_t pdev_id;
+	struct wlan_scan_obj *scan_obj;
+
+	if (!vdev) {
+		scm_warn("null vdev");
+		QDF_ASSERT(0);
+		return 0;
+	}
+	pdev_id = wlan_scan_vdev_get_pdev_id(vdev);
+	scan_obj = wlan_vdev_get_scan_obj(vdev);
+
+	return scan_obj->pdev_info[pdev_id].last_scan_time;
+}