Browse Source

qcacmn: Provide implementation of command queue operations

Provide the implementation to enqueue, dequeue, cancel,
remove, flush operation of command.

Change-Id: Id62cf320fa0936ed3ddb1264464d35ab5c60e95a
CRs-Fixed: 2000032
Krunal Soni 8 years ago
parent
commit
16641b145a

+ 2 - 2
umac/cmn_services/serialization/inc/wlan_serialization_api.h

@@ -192,7 +192,7 @@ struct wlan_serialization_command {
 	enum wlan_serialization_cmd_type cmd_type;
 	uint16_t cmd_id;
 	wlan_serialization_cmd_callback cmd_cb;
-	uint8_t source;
+	enum wlan_umac_comp_id source;
 	bool is_high_priority;
 	uint16_t cmd_timeout_duration;
 	union {
@@ -211,7 +211,7 @@ struct wlan_serialization_command {
  * @queue_type: Queues from which the command to be cancelled
  */
 struct wlan_serialization_queued_cmd_info {
-	uint8_t requestor;
+	enum wlan_umac_comp_id requestor;
 	enum wlan_serialization_cmd_type cmd_type;
 	uint16_t cmd_id;
 	enum wlan_serialization_cancel_type req_type;

+ 46 - 2
umac/cmn_services/serialization/src/wlan_serialization_api.c

@@ -26,6 +26,7 @@
 /* Include files */
 #include "wlan_objmgr_psoc_obj.h"
 #include "wlan_serialization_main_i.h"
+#include "wlan_serialization_utils_i.h"
 
 QDF_STATUS
 wlan_serialization_register_comp_info_cb(struct wlan_objmgr_psoc *psoc,
@@ -99,15 +100,40 @@ enum wlan_serialization_cmd_status
 wlan_serialization_cancel_request(
 		struct wlan_serialization_queued_cmd_info *req)
 {
+	QDF_STATUS status;
+
 	serialization_info("serialization cancel request entry");
+	if (!req) {
+		serialization_err("given request is empty");
+		return WLAN_SER_CMD_NOT_FOUND;
+	}
+	status = wlan_serialization_validate_cmd(req->requestor, req->cmd_type);
+	if (status != QDF_STATUS_SUCCESS) {
+		serialization_err("req is not valid");
+		return WLAN_SER_CMD_NOT_FOUND;
+	}
 
-	return WLAN_SER_CMD_NOT_FOUND;
+	return wlan_serialization_find_and_cancel_cmd(req);
 }
 
 void wlan_serialization_remove_cmd(
 		struct wlan_serialization_queued_cmd_info *cmd)
 {
+	QDF_STATUS status;
+
 	serialization_info("serialization remove request entry");
+	if (!cmd) {
+		serialization_err("given request is empty");
+		QDF_ASSERT(0);
+		return;
+	}
+	status = wlan_serialization_validate_cmd(cmd->requestor, cmd->cmd_type);
+	if (status != QDF_STATUS_SUCCESS) {
+		serialization_err("cmd is not valid");
+		QDF_ASSERT(0);
+		return;
+	}
+	wlan_serialization_find_and_remove_cmd(cmd);
 
 	return;
 }
@@ -115,15 +141,33 @@ void wlan_serialization_remove_cmd(
 enum wlan_serialization_status
 wlan_serialization_request(struct wlan_serialization_command *cmd)
 {
+	bool is_active_cmd_allowed;
+	QDF_STATUS status;
+
 	serialization_info("serialization queue cmd entry");
+	if (!cmd) {
+		serialization_err("serialization cmd is null");
+		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
+	}
+	status = wlan_serialization_validate_cmd(cmd->source, cmd->cmd_type);
+	if (status != QDF_STATUS_SUCCESS) {
+		serialization_err("cmd is not valid");
+		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
+	}
 
-	return WLAN_SER_CMD_NOT_FOUND;
+	is_active_cmd_allowed = wlan_serialization_is_active_cmd_allowed(cmd);
+	return wlan_serialization_enqueue_cmd(cmd, is_active_cmd_allowed);
 }
 
 void wlan_serialization_flush_cmd(
 		struct wlan_serialization_queued_cmd_info *cmd)
 {
 	serialization_info("serialization cmd flushed");
+	if (!cmd) {
+		serialization_err("cmd is null, can't flush");
+		return;
+	}
+	/* TODO: discuss and fill this API later */
 
 	return;
 }

+ 568 - 0
umac/cmn_services/serialization/src/wlan_serialization_dequeue.c

@@ -20,4 +20,572 @@
  * This file defines the routines which are pertinent
  * to the dequeue of commands.
  */
+#include <wlan_serialization_api.h>
+#include "wlan_serialization_main_i.h"
+#include "wlan_serialization_utils_i.h"
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <qdf_list.h>
+
+void wlan_serialization_move_pending_to_active(
+		enum wlan_serialization_cmd_type cmd_type,
+		struct wlan_serialization_pdev_priv_obj *ser_pdev_obj)
+{
+	qdf_list_t *pending_queue;
+	struct wlan_serialization_command_list *cmd_list;
+	enum wlan_serialization_status status;
+	qdf_list_node_t *nnode = NULL;
+
+	if (!ser_pdev_obj) {
+		serialization_err("Can't find ser_pdev_obj");
+		return;
+	}
+
+	if (cmd_type == WLAN_SER_CMD_SCAN)
+		pending_queue = &ser_pdev_obj->pending_scan_list;
+	else
+		pending_queue = &ser_pdev_obj->pending_list;
+
+	if (qdf_list_empty(pending_queue)) {
+		serialization_info("nothing to move from pend to active queue");
+		serialization_info("cmd_type - %d", cmd_type);
+		return;
+	}
+	if (QDF_STATUS_SUCCESS != qdf_list_peek_front(pending_queue, &nnode)) {
+		serialization_err("can't read from pending queue");
+		serialization_info("cmd_type - %d", cmd_type);
+		return;
+	}
+	cmd_list = qdf_container_of(nnode,
+			struct wlan_serialization_command_list, node);
+	/*
+	 * Idea is to peek command from pending queue, and try to
+	 * push to active queue. If command goes to active queue
+	 * successfully then remove the command from pending queue which
+	 * we previously peeked.
+	 *
+	 * By doing this way, we will make sure that command will be removed
+	 * from pending queue only when it was able to make it to active queue
+	 */
+	status = wlan_serialization_enqueue_cmd(&cmd_list->cmd, true);
+	if (WLAN_SER_CMD_ACTIVE != status) {
+		serialization_err("Can't move cmd to activeQ id-%d type-%d",
+				cmd_list->cmd.cmd_id, cmd_list->cmd.cmd_type);
+		return;
+	}
+	wlan_serialization_put_back_to_global_list(pending_queue,
+				ser_pdev_obj, cmd_list);
+
+	return;
+}
+
+
+/**
+ * wlan_serialization_remove_all_cmd_from_queue() - Remove cmd which matches
+ * @queue: queue from where command needs to be removed
+ * @ser_pdev_obj: pointer to serialization object
+ * @pdev: pointer to pdev
+ * @vdev: pointer to vdev
+ * @cmd: pointer to cmd
+ * @is_active_queue: to check if command matching is for active queue
+ *
+ * This API will remove one or more commands which match the given parameters
+ * interms of argument. For example, if user request all commands to removed
+ * which matches "vdev" then iterate through all commands, find out and remove
+ * command which matches vdev object.
+ *
+ * Return: enum wlan_serialization_cmd_status
+ */
+static enum wlan_serialization_cmd_status
+wlan_serialization_remove_all_cmd_from_queue(qdf_list_t *queue,
+		struct wlan_serialization_pdev_priv_obj *ser_pdev_obj,
+		struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev,
+		struct wlan_serialization_command *cmd, uint8_t is_active_queue)
+{
+	uint32_t qsize;
+	struct wlan_serialization_command_list *cmd_list;
+	qdf_list_node_t *nnode = NULL, *pnode = NULL;
+	enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND;
+	QDF_STATUS qdf_status;
+
+	qsize = qdf_list_size(queue);
+	while (qsize--) {
+		if (wlan_serialization_get_cmd_from_queue(queue, &nnode)
+				!= QDF_STATUS_SUCCESS) {
+			serialization_err("can't read cmd from queue");
+			status = WLAN_SER_CMD_NOT_FOUND;
+			break;
+		}
+		cmd_list = qdf_container_of(nnode,
+				struct wlan_serialization_command_list, node);
+		if ((cmd && ((cmd->cmd_id != cmd_list->cmd.cmd_id) ||
+				(cmd->cmd_type != cmd_list->cmd.cmd_type))) ||
+			(vdev && (vdev != cmd_list->cmd.vdev)) ||
+			(pdev && (pdev != wlan_vdev_get_pdev(
+						cmd_list->cmd.vdev)))) {
+			pnode = nnode;
+			continue;
+		}
+		/*
+		 * active queue can't be removed directly, requester needs to
+		 * wait for active command response and send remove request for
+		 * active command seperately
+		 */
+		if (is_active_queue) {
+			status = WLAN_SER_CMD_IN_ACTIVE_LIST;
+			break;
+		}
+		/*
+		 * call pending cmd's callback to notify that
+		 * it is being removed
+		 */
+		if (cmd_list->cmd.cmd_cb) {
+			/* caller should now do necessary clean up */
+			cmd_list->cmd.cmd_cb(&cmd_list->cmd,
+					WLAN_SER_CB_CANCEL_CMD);
+			/* caller should release the memory */
+			cmd_list->cmd.cmd_cb(&cmd_list->cmd,
+					WLAN_SER_CB_RELEASE_MEM_CMD);
+		}
+
+		qdf_status = wlan_serialization_put_back_to_global_list(queue,
+				ser_pdev_obj, cmd_list);
+		if (QDF_STATUS_SUCCESS != qdf_status) {
+			serialization_err("can't remove cmd from queue");
+			status = WLAN_SER_CMD_NOT_FOUND;
+			break;
+		}
+		nnode = pnode;
+		/* If cmd was on active list then we wouldn't have come here */
+		status = WLAN_SER_CMD_IN_PENDING_LIST;
+	}
+
+	return status;
+}
+
+/**
+ * wlan_serialization_remove_cmd_from_given_queue() - to remove command from
+ *							given queue
+ * @queue: queue from which command needs to be removed
+ * @cmd: command to match in the queue
+ * @ser_pdev_obj: pointer to private pdev serialization object
+ *
+ * This API takes the queue, it matches the provided command from this queue
+ * and removes it. Before removing the command, it will notify the caller
+ * that if it needs to remove any memory allocated by caller.
+ *
+ * Return: none
+ */
+static void wlan_serialization_remove_cmd_from_given_queue(qdf_list_t *queue,
+		struct wlan_serialization_command *cmd,
+		struct wlan_serialization_pdev_priv_obj *ser_pdev_obj)
+{
+	uint32_t qsize;
+	struct wlan_serialization_command_list *cmd_list;
+	qdf_list_node_t *nnode = NULL;
+	QDF_STATUS status;
+
+	if (!cmd)
+		return;
+
+	qsize = qdf_list_size(queue);
+
+	while (qsize--) {
+		status = wlan_serialization_get_cmd_from_queue(queue, &nnode);
+		if (status != QDF_STATUS_SUCCESS) {
+			serialization_err("can't peek cmd_id[%d] type[%d]",
+					  cmd->cmd_id, cmd->cmd_type);
+			break;
+		}
+		cmd_list = qdf_container_of(nnode,
+				struct wlan_serialization_command_list, node);
+		if ((cmd_list->cmd.cmd_id != cmd->cmd_id) ||
+				(cmd_list->cmd.cmd_type != cmd->cmd_type))
+			continue;
+		if (cmd_list->cmd.vdev != cmd->vdev)
+			continue;
+		if (cmd_list->cmd.cmd_cb) {
+			/* caller should release the memory */
+			cmd_list->cmd.cmd_cb(&cmd_list->cmd,
+					WLAN_SER_CB_RELEASE_MEM_CMD);
+		}
+		status = wlan_serialization_put_back_to_global_list(queue,
+				ser_pdev_obj, cmd_list);
+
+		if (QDF_STATUS_SUCCESS != status)
+			serialization_err("Fail to add to free pool type[%d]",
+					  cmd->cmd_type);
+		/*
+		 * zero out the command, so caller would know that command has
+		 * been removed
+		 */
+		qdf_mem_zero(cmd, sizeof(struct wlan_serialization_command));
+		break;
+	}
+}
+
+/**
+ * wlan_serialization_remove_cmd_from_active_queue() - helper function to remove
+ *							cmd from active queue
+ * @psoc: pointer to psoc
+ * @obj: pointer to object getting passed by object manager
+ * @arg: argument passed by caller to object manager which comes to this cb
+ *
+ * caller provide this API as callback to object manager, and in turn
+ * object manager iterate through each pdev and call this API callback.
+ *
+ * Return: none
+ */
+static void
+wlan_serialization_remove_cmd_from_active_queue(struct wlan_objmgr_psoc *psoc,
+		void *obj, void *arg)
+{
+	qdf_list_t *queue;
+	struct wlan_objmgr_pdev *pdev = obj;
+	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
+	struct wlan_serialization_command *cmd = arg;
+
+	if (!pdev || !cmd) {
+		serialization_err("Invalid param");
+		return;
+	}
+
+	ser_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+			WLAN_UMAC_COMP_SERIALIZATION);
+	if (!ser_pdev_obj) {
+		serialization_err("Invalid ser_pdev_obj");
+		return;
+	}
+
+	if (cmd->cmd_type == WLAN_SER_CMD_SCAN)
+		queue = &ser_pdev_obj->active_scan_list;
+	else
+		queue = &ser_pdev_obj->active_list;
+
+	if (qdf_list_empty(queue)) {
+		serialization_err("Empty queue");
+		return;
+	}
+
+	wlan_serialization_remove_cmd_from_given_queue(queue, cmd,
+			ser_pdev_obj);
+
+	return;
+}
+
+/**
+ * wlan_serialization_remove_cmd_from_active_queue() - helper function to remove
+ *							cmd from pending queue
+ * @psoc: pointer to psoc
+ * @obj: pointer to object getting passed by object manager
+ * @arg: argument passed by caller to object manager which comes to this cb
+ *
+ * caller provide this API as callback to object manager, and in turn
+ * object manager iterate through each pdev and call this API callback.
+ *
+ * Return: none
+ */
+static void
+wlan_serialization_remove_cmd_from_pending_queue(struct wlan_objmgr_psoc *psoc,
+		void *obj, void *arg)
+{
+	qdf_list_t *queue;
+	struct wlan_objmgr_pdev *pdev = obj;
+	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
+	struct wlan_serialization_command *cmd = arg;
+
+	if (!pdev || !cmd) {
+		serialization_err("Invalid param");
+		return;
+	}
+
+	ser_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+			WLAN_UMAC_COMP_SERIALIZATION);
+	if (!ser_pdev_obj) {
+		serialization_err("Invalid ser_pdev_obj");
+		return;
+	}
+
+	if (cmd->cmd_type == WLAN_SER_CMD_SCAN)
+		queue = &ser_pdev_obj->pending_scan_list;
+	else
+		queue = &ser_pdev_obj->pending_list;
+
+	if (qdf_list_empty(queue)) {
+		serialization_err("Empty queue");
+		return;
+	}
+	wlan_serialization_remove_cmd_from_given_queue(queue,
+			cmd, ser_pdev_obj);
+
+	return;
+}
+
+/**
+ * wlan_serialization_is_cmd_removed() - to check if requested command is
+ *						removed
+ * @psoc: pointer to soc
+ * @cmd: given command to remove
+ * @check_active_queue: flag to find out whether command needs to be removed
+ *			from active queue or pending queue
+ *
+ * Return: true if removed else false
+ */
+static bool
+wlan_serialization_is_cmd_removed(struct wlan_objmgr_psoc *psoc,
+		struct wlan_serialization_command *cmd,
+		bool check_active_queue)
+{
+	if (!psoc) {
+		serialization_err("Invalid psoc");
+		return false;
+	}
+
+	if (check_active_queue)
+		wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
+			wlan_serialization_remove_cmd_from_active_queue,
+				cmd, 0);
+	else
+		wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
+			wlan_serialization_remove_cmd_from_pending_queue,
+			cmd, 0);
+
+	if (cmd->vdev == NULL)
+		return true;
+
+	return false;
+}
+
+enum wlan_serialization_cmd_status
+wlan_serialization_dequeue_cmd(struct wlan_serialization_command *cmd,
+		uint8_t only_active_cmd)
+{
+	enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
+	struct wlan_serialization_command cmd_backup;
+	enum wlan_serialization_cmd_type cmd_type;
+	bool is_cmd_removed;
+
+	if (!cmd) {
+		serialization_err("NULL command");
+		return status;
+	}
+	/* Dequeue process
+	 * 1) peek through command structure and see what is the command type
+	 * 2) two main types of commands to process
+	 *    a) SCAN
+	 *    b) NON-SCAN
+	 * 3) for each command there are seperate command queues per pdev
+	 * 4) iterate through every pdev object and find the command and remove
+	 */
+
+	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
+
+	if (pdev == NULL) {
+		serialization_err("invalid pdev");
+		return status;
+	}
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (psoc == NULL) {
+		serialization_err("invalid psoc");
+		return status;
+	}
+
+	/* get priv object by wlan_objmgr_vdev_get_comp_private_obj */
+	ser_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(
+			pdev, WLAN_UMAC_COMP_SERIALIZATION);
+	if (!ser_pdev_obj) {
+		serialization_err("ser_pdev_obj is empty");
+		return status;
+	}
+	/*
+	 *  Pass the copy of command, instead of actual command because
+	 *  wlan_serialization_is_cmd_removed() api cleans the command
+	 *  buffer up on successful removal. We may need to use the command's
+	 *  content to stop the timer and etc.
+	 */
+	qdf_mem_copy(&cmd_backup, cmd,
+			sizeof(struct wlan_serialization_command));
+
+	cmd_type = cmd->cmd_type;
+	/* find and remove from active list */
+	if (only_active_cmd) {
+		wlan_serialization_find_and_stop_timer(psoc, cmd);
+		is_cmd_removed = wlan_serialization_is_cmd_removed(psoc,
+						&cmd_backup, true);
+		if (true == is_cmd_removed) {
+			/*
+			 * command is removed from active queue. now we have a
+			 * room in active queue, so we will move from relevant
+			 * pending queue to active queue
+			 */
+			wlan_serialization_move_pending_to_active(cmd_type,
+					ser_pdev_obj);
+			status = WLAN_SER_CMD_IN_ACTIVE_LIST;
+		} else {
+			serialization_err("cmd_type[%d], cmd_id[%d], vdev[%p]",
+					cmd->cmd_type, cmd->cmd_id, cmd->vdev);
+			/*
+			 * if you come here means there is a possibility
+			 * that we couldn't find the command in active queue
+			 * which user has requested to remove or we couldn't
+			 * remove command from active queue and timer has been
+			 * stopped, so active queue may possibly stuck.
+			 */
+			QDF_ASSERT(0);
+			status = WLAN_SER_CMD_NOT_FOUND;
+		}
+		serialization_info("Request to remove only from active queue");
+		return status;
+	}
+	qdf_mem_copy(&cmd_backup, cmd,
+			sizeof(struct wlan_serialization_command));
+	/* find and remove from pending list */
+	if (wlan_serialization_is_cmd_removed(psoc, &cmd_backup, false)) {
+		if (status != WLAN_SER_CMD_IN_ACTIVE_LIST)
+			status = WLAN_SER_CMD_IN_PENDING_LIST;
+		else
+			status = WLAN_SER_CMDS_IN_ALL_LISTS;
+	}
+
+	return status;
+}
+
+/**
+ * wlan_serialization_cmd_cancel_handler() - helper func to cancel cmd
+ * @ser_obj: private pdev ser obj
+ * @cmd: pointer to command
+ * @pdev: pointer to pdev
+ * @vdev: pointer to vdev
+ * @cmd_type: pointer to cmd_type
+ *
+ * This API will decide from which queue, command needs to be cancelled
+ * and pass that queue and other parameter required to cancel the command
+ * to helper function.
+ *
+ * Return: wlan_serialization_cmd_status
+ */
+static enum wlan_serialization_cmd_status
+wlan_serialization_cmd_cancel_handler(
+		struct wlan_serialization_pdev_priv_obj *ser_obj,
+		struct wlan_serialization_command *cmd,
+		struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev,
+		enum wlan_serialization_cmd_type cmd_type)
+{
+	enum wlan_serialization_cmd_status status;
+	qdf_list_t *queue;
+
+	if (!ser_obj) {
+		serialization_err("invalid serial object");
+		return WLAN_SER_CMD_NOT_FOUND;
+	}
+	/* remove pending commands first */
+	if (cmd_type == WLAN_SER_CMD_SCAN)
+		queue = &ser_obj->pending_scan_list;
+	else
+		queue = &ser_obj->pending_list;
+	/* try and remove first from pending list */
+	status = wlan_serialization_remove_all_cmd_from_queue(queue,
+			ser_obj, pdev, vdev, cmd, false);
+	if (cmd_type == WLAN_SER_CMD_SCAN)
+		queue = &ser_obj->active_scan_list;
+	else
+		queue = &ser_obj->active_list;
+	/* try and remove next from active list */
+	if (WLAN_SER_CMD_IN_ACTIVE_LIST ==
+			wlan_serialization_remove_all_cmd_from_queue(queue,
+				ser_obj, pdev, vdev, cmd, true)) {
+		if (WLAN_SER_CMD_IN_PENDING_LIST == status)
+			status = WLAN_SER_CMDS_IN_ALL_LISTS;
+		else
+			status = WLAN_SER_CMD_IN_ACTIVE_LIST;
+	}
+
+	return status;
+}
+
+enum wlan_serialization_cmd_status
+wlan_serialization_find_and_cancel_cmd(
+		struct wlan_serialization_queued_cmd_info *cmd_info)
+{
+	struct wlan_serialization_command cmd;
+	enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND;
+	struct wlan_serialization_pdev_priv_obj *ser_obj = NULL;
+	struct wlan_objmgr_pdev *pdev;
+
+	if (!cmd_info) {
+		serialization_err("Invalid cmd_info");
+		return WLAN_SER_CMD_NOT_FOUND;
+	}
+	cmd.cmd_id = cmd_info->cmd_id;
+	cmd.cmd_type = cmd_info->cmd_type;
+	cmd.vdev = cmd_info->vdev;
+	pdev = wlan_serialization_get_pdev_from_cmd(&cmd);
+	if (!pdev) {
+		serialization_err("Invalid pdev");
+		return WLAN_SER_CMD_NOT_FOUND;
+	}
+	ser_obj = wlan_serialization_get_pdev_priv_obj(pdev);
+	if (!ser_obj) {
+		serialization_err("Invalid ser_obj");
+		return WLAN_SER_CMD_NOT_FOUND;
+	}
+
+	switch (cmd_info->req_type) {
+	case WLAN_SER_CANCEL_SINGLE_SCAN:
+		/* remove scan cmd which matches the given cmd struct */
+		status =  wlan_serialization_cmd_cancel_handler(ser_obj,
+				&cmd, NULL, NULL, cmd.cmd_type);
+		break;
+	case WLAN_SER_CANCEL_PDEV_SCANS:
+		/* remove all scan cmds which matches the pdev object */
+		status = wlan_serialization_cmd_cancel_handler(ser_obj,
+				NULL,
+				wlan_vdev_get_pdev(cmd.vdev),
+				NULL, cmd.cmd_type);
+		break;
+	case WLAN_SER_CANCEL_VDEV_SCANS:
+		/* remove all scan cmds which matches the vdev object */
+		status = wlan_serialization_cmd_cancel_handler(ser_obj,
+				NULL, NULL,
+				cmd.vdev, cmd.cmd_type);
+		break;
+	case WLAN_SER_CANCEL_NON_SCAN_CMD:
+		/* remove nonscan cmd which matches the given cmd */
+		status = wlan_serialization_cmd_cancel_handler(ser_obj,
+				&cmd, NULL, NULL, cmd.cmd_type);
+		break;
+	default:
+		serialization_err("Invalid request");
+	}
+
+	return status;
+}
+
+QDF_STATUS wlan_serialization_find_and_remove_cmd(
+		struct wlan_serialization_queued_cmd_info *cmd_info)
+{
+	struct wlan_serialization_command cmd;
+
+	if (!cmd_info) {
+		serialization_err("Invalid cmd_info");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	cmd.cmd_id = cmd_info->cmd_id;
+	cmd.cmd_type = cmd_info->cmd_type;
+	cmd.vdev = cmd_info->vdev;
+	if (WLAN_SER_CMD_IN_ACTIVE_LIST !=
+			wlan_serialization_dequeue_cmd(&cmd, true)) {
+		serialization_err("Can't dequeue requested cmd_id[%d] type[%d]",
+				cmd_info->cmd_id, cmd_info->cmd_type);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
 

+ 167 - 0
umac/cmn_services/serialization/src/wlan_serialization_enqueue.c

@@ -20,4 +20,171 @@
  * This file defines the routines which are pertinent
  * to the queuing of commands.
  */
+#include <wlan_serialization_api.h>
+#include "wlan_serialization_main_i.h"
+#include "wlan_serialization_utils_i.h"
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <qdf_list.h>
 
+static enum wlan_serialization_status
+wlan_serialization_add_cmd_to_given_queue(qdf_list_t *queue,
+			struct wlan_serialization_command *cmd,
+			struct wlan_objmgr_psoc *psoc,
+			struct wlan_serialization_pdev_priv_obj *ser_pdev_obj,
+			uint8_t is_cmd_for_active_queue)
+{
+	struct wlan_serialization_command_list *cmd_list;
+	enum wlan_serialization_status status;
+	QDF_STATUS qdf_status;
+	qdf_list_node_t *nnode;
+
+	if (!cmd || !queue || !ser_pdev_obj || !psoc) {
+		serialization_err("Input arguments are not valid");
+		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
+	}
+	if (qdf_list_empty(&ser_pdev_obj->global_cmd_pool_list)) {
+		serialization_err("list is full, can't add more");
+		QDF_BUG(0);
+		return WLAN_SER_CMD_DENIED_LIST_FULL;
+	}
+	if (qdf_list_remove_front(&ser_pdev_obj->global_cmd_pool_list,
+				&nnode) != QDF_STATUS_SUCCESS) {
+		serialization_err("Failed to get cmd buffer from global pool");
+		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
+	}
+	cmd_list = qdf_container_of(nnode,
+			struct wlan_serialization_command_list, node);
+	qdf_mem_copy(&cmd_list->cmd, cmd,
+			sizeof(struct wlan_serialization_command));
+	if (cmd->is_high_priority)
+		qdf_status = qdf_list_insert_front(queue, &cmd_list->node);
+	else
+		qdf_status = qdf_list_insert_back(queue, &cmd_list->node);
+	if (qdf_status != QDF_STATUS_SUCCESS) {
+		serialization_err("can't queue command for cmd_id-%d type-%d",
+				cmd->cmd_id, cmd->cmd_type);
+		qdf_mem_zero(&cmd_list->cmd,
+				sizeof(struct wlan_serialization_command));
+		qdf_status = qdf_list_insert_back(
+					&ser_pdev_obj->global_cmd_pool_list,
+					&cmd_list->node);
+		if (QDF_STATUS_SUCCESS != qdf_status) {
+			serialization_err("can't put cmd back to global pool");
+			QDF_ASSERT(0);
+		}
+		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
+	}
+
+	if (is_cmd_for_active_queue) {
+		/*
+		 * command is already pushed to active queue above
+		 * now start the timer and notify requestor
+		 */
+		wlan_serialization_find_and_start_timer(psoc,
+							&cmd_list->cmd);
+		if (cmd_list->cmd.cmd_cb) {
+			/*
+			 * Remember that serialization module may send
+			 * this callback in same context through which it
+			 * received the serialization request. Due to which
+			 * it is caller's responsibility to ensure acquiring
+			 * and releasing its own lock appropriately.
+			 */
+			qdf_status = cmd_list->cmd.cmd_cb(&cmd_list->cmd,
+						WLAN_SER_CB_ACTIVATE_CMD);
+			if (qdf_status != QDF_STATUS_SUCCESS) {
+				wlan_serialization_find_and_stop_timer(psoc,
+								&cmd_list->cmd);
+				wlan_serialization_put_back_to_global_list(
+						queue, ser_pdev_obj, cmd_list);
+				wlan_serialization_move_pending_to_active(
+						cmd_list->cmd.cmd_type,
+						ser_pdev_obj);
+			}
+		}
+		status = WLAN_SER_CMD_ACTIVE;
+	} else {
+		status = WLAN_SER_CMD_PENDING;
+	}
+
+	return status;
+}
+
+enum wlan_serialization_status
+wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd,
+			       uint8_t is_cmd_for_active_queue)
+{
+	enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
+	qdf_list_t *queue;
+
+	/* Enqueue process
+	 * 1) peek through command structure and see what is the command type
+	 * 2) two main types of commands to process
+	 *    a) SCAN
+	 *    b) NON-SCAN
+	 * 3) for each command there are seperate command queues per pdev
+	 * 4) pull pdev from vdev structure and get the command queue associated
+	 *    with that pdev and try to enqueue on those queue
+	 * 5) Thumb rule:
+	 *    a) There could be only 1 active non-scan command at a
+	 *       time including all total non-scan commands of all pdevs.
+	 *
+	 *       example: pdev1 has 1 non-scan active command and
+	 *       pdev2 got 1 non-scan command then that command should go to
+	 *       pdev2's pending queue
+	 *
+	 *    b) There could be only N number of scan commands at a time
+	 *       including all total scan commands of all pdevs
+	 *
+	 *       example: Let's say N=8,
+	 *       pdev1's vdev1 has 5 scan command, pdev2's vdev1 has 3
+	 *       scan commands, if we get scan request on vdev2 then it will go
+	 *       to pending queue of vdev2 as we reached max allowed scan active
+	 *       command.
+	 */
+	if (!cmd) {
+		serialization_err("NULL command");
+		return status;
+	}
+	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
+	if (pdev == NULL) {
+		serialization_err("invalid pdev");
+		return status;
+	}
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (psoc == NULL) {
+		serialization_err("invalid psoc");
+		return status;
+	}
+
+	/* get priv object by wlan_objmgr_vdev_get_comp_private_obj */
+	ser_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(
+			pdev, WLAN_UMAC_COMP_SERIALIZATION);
+	if (!ser_pdev_obj) {
+		serialization_err("Can't find ser_pdev_obj");
+		return status;
+	}
+
+	serialization_debug("command high_priority[%d] cmd_type[%d] cmd_id[%d]",
+			cmd->is_high_priority, cmd->cmd_type, cmd->cmd_id);
+	if (cmd->cmd_type == WLAN_SER_CMD_SCAN) {
+		if (is_cmd_for_active_queue)
+			queue = &ser_pdev_obj->active_scan_list;
+		else
+			queue = &ser_pdev_obj->pending_scan_list;
+	} else {
+		if (is_cmd_for_active_queue)
+			queue = &ser_pdev_obj->active_list;
+		else
+			queue = &ser_pdev_obj->pending_list;
+	}
+
+	return wlan_serialization_add_cmd_to_given_queue(queue, cmd, psoc,
+			ser_pdev_obj, is_cmd_for_active_queue);
+}

+ 10 - 4
umac/cmn_services/serialization/src/wlan_serialization_main.c

@@ -29,6 +29,7 @@
 #include "wlan_objmgr_psoc_obj.h"
 #include "wlan_serialization_main_i.h"
 #include "wlan_serialization_rules_i.h"
+#include "wlan_serialization_utils_i.h"
 
 /**
  * wlan_serialization_apply_rules_cb_init() - Apply rule callback init
@@ -95,6 +96,11 @@ QDF_STATUS wlan_serialization_psoc_close(struct wlan_objmgr_psoc *psoc)
 		serialization_err("invalid ser_soc_obj");
 		return QDF_STATUS_E_FAILURE;
 	}
+	/* clean up all timers before exiting */
+	status = wlan_serialization_cleanup_all_timers(ser_soc_obj);
+	if (status != QDF_STATUS_SUCCESS)
+		serialization_err("ser cleanning up all timer failed");
+
 	qdf_mem_free(ser_soc_obj->timers);
 	ser_soc_obj->timers = NULL;
 	ser_soc_obj->max_active_cmds = 0;
@@ -160,15 +166,15 @@ static void wlan_serialization_destroy_cmd_pool(
 {
 
 	qdf_list_node_t *node = NULL;
-	struct wlan_serialization_command_list *cmd_list_node;
+	struct wlan_serialization_command_list *cmd_list;
 
 	while (!qdf_list_empty(&ser_pdev_obj->global_cmd_pool_list)) {
 		qdf_list_remove_front(&ser_pdev_obj->global_cmd_pool_list,
 				&node);
-		cmd_list_node = (struct wlan_serialization_command_list *)node;
+		cmd_list = (struct wlan_serialization_command_list *)node;
 		serialization_info("Node being freed from global pool %p",
-				cmd_list_node);
-		qdf_mem_free(cmd_list_node);
+				cmd_list);
+		qdf_mem_free(cmd_list);
 
 	}
 	qdf_list_destroy(&ser_pdev_obj->global_cmd_pool_list);

+ 0 - 33
umac/cmn_services/serialization/src/wlan_serialization_main_i.h

@@ -26,9 +26,6 @@
 #include "wlan_objmgr_cmn.h"
 #include "wlan_objmgr_psoc_obj.h"
 #include "wlan_objmgr_pdev_obj.h"
-#include "wlan_serialization_api.h"
-#include "wlan_serialization_rules_i.h"
-#include "wlan_serialization_utils_i.h"
 #include "qdf_mc_timer.h"
 
 #define WLAN_SERIALIZATION_MAX_GLOBAL_POOL_CMDS 24
@@ -53,36 +50,6 @@
 #define serialization_debug(format, args...) \
 	serialization_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args)
 
-
-/**
- * struct wlan_serialization_timer - Timer used for serialization
- * @cmd:      Cmd to which the timer is linked
- * @timer:    Timer associated with the command
- *
- * Timers are allocated statically during init, one each for the
- * maximum active commands permitted in the system. Once a cmd is
- * moved from pending list to active list, the timer is activated
- * and once the cmd is completed, the timer is cancelled. Timer is
- * also cancelled if the command is aborted
- *
- * The timers are maintained per psoc. A timer is associated to
- * unique combination of pdev, cmd_type and cmd_id.
- */
-struct wlan_serialization_timer {
-	struct wlan_serialization_command *cmd;
-	qdf_mc_timer_t timer;
-};
-
-/**
- * struct wlan_serialization_command_list - List of commands to be serialized
- * @node: Node identifier in the list
- * @cmd: Command to be serialized
- */
-struct wlan_serialization_command_list {
-	qdf_list_node_t node;
-	struct wlan_serialization_command cmd;
-};
-
 /**
  * wlan_serialization_psoc_obj_create_notification() - PSOC obj create callback
  * @psoc: PSOC object

+ 2 - 1
umac/cmn_services/serialization/src/wlan_serialization_rules.c

@@ -16,7 +16,8 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "wlan_serialization_main_i.h"
+#include "wlan_serialization_rules_i.h"
+
 bool wlan_apply_scan_rules(union wlan_serialization_rules_info *info)
 {
 	return true;

+ 1 - 0
umac/cmn_services/serialization/src/wlan_serialization_rules_i.h

@@ -22,6 +22,7 @@
  */
 #ifndef __WLAN_SERIALIZATION_RULES_I_H
 #define __WLAN_SERIALIZATION_RULES_I_H
+#include "wlan_serialization_api.h"
 /**
  * wlan_apply_scan_rules() - Apply scan rules
  * @status: return information status fetched from other components

+ 412 - 0
umac/cmn_services/serialization/src/wlan_serialization_utils.c

@@ -21,6 +21,418 @@
  */
 
 #include "wlan_serialization_utils_i.h"
+#include "wlan_serialization_main_i.h"
+#include "wlan_serialization_api.h"
+#include "wlan_objmgr_vdev_obj.h"
+#include "wlan_objmgr_pdev_obj.h"
+#include "qdf_mc_timer.h"
+
+QDF_STATUS
+wlan_serialization_put_back_to_global_list(qdf_list_t *queue,
+		struct wlan_serialization_pdev_priv_obj *ser_pdev_obj,
+		struct wlan_serialization_command_list *cmd_list)
+{
+	QDF_STATUS status;
+
+	if (!queue || !ser_pdev_obj || !cmd_list) {
+		serialization_err("input parameters are invalid");
+		return QDF_STATUS_E_FAILURE;
+	}
+	status = qdf_list_remove_node(queue, &cmd_list->node);
+	if (QDF_STATUS_SUCCESS != status) {
+		serialization_err("can't remove cmd from queue");
+		/* assert to catch any leaks */
+		QDF_ASSERT(0);
+		return status;
+	}
+	serialization_info("cmd_id-%d, cmd_type-%d", cmd_list->cmd.cmd_id,
+				cmd_list->cmd.cmd_type);
+	qdf_mem_zero(&cmd_list->cmd, sizeof(struct wlan_serialization_command));
+	status = qdf_list_insert_back(&ser_pdev_obj->global_cmd_pool_list,
+					&cmd_list->node);
+	if (QDF_STATUS_SUCCESS != status) {
+		serialization_err("can't put command back to global pool");
+		QDF_ASSERT(0);
+		return status;
+	}
+
+	return status;
+}
+
+struct wlan_objmgr_pdev*
+wlan_serialization_get_pdev_from_cmd(struct wlan_serialization_command *cmd)
+{
+	struct wlan_objmgr_pdev *pdev = NULL;
+
+	if (!cmd) {
+		serialization_err("invalid cmd");
+		return pdev;
+	}
+	pdev = wlan_vdev_get_pdev(cmd->vdev);
+
+	return pdev;
+}
+
+/**
+ * wlan_serialization_get_cmd_from_queue() - to extract command from given queue
+ * @queue: pointer to queue
+ * @nnode: next node to extract
+ *
+ * This API will try to extract node from queue which is next to prev node. If
+ * no previous node is given then take out the front node of the queue.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_serialization_get_cmd_from_queue(qdf_list_t *queue,
+						 qdf_list_node_t **nnode)
+{
+	QDF_STATUS status;
+	qdf_list_node_t *pnode;
+
+	pnode = *nnode;
+	if (!pnode)
+		status = qdf_list_peek_front(queue, nnode);
+	else
+		status = qdf_list_peek_next(queue, pnode, nnode);
+
+	if (status != QDF_STATUS_SUCCESS) {
+		serialization_err("can't get next node from queue");
+		return status;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wlan_serialization_timer_destroy() - destroys the timer
+ * @ser_timer: pointer to particular timer
+ *
+ * This API destroys the memory allocated by timer and assigns cmd member of
+ * that timer structure to NULL
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS wlan_serialization_timer_destroy(
+		struct wlan_serialization_timer *ser_timer)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	if (!ser_timer || !ser_timer->cmd) {
+		serialization_debug("Invalid ser_timer");
+		return status;
+	}
+	status = qdf_mc_timer_destroy(&ser_timer->timer);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		serialization_err("Failed to destroy timer for cmd_id[%d]",
+				ser_timer->cmd->cmd_id);
+		QDF_ASSERT(0);
+		return status;
+	}
+	ser_timer->cmd = NULL;
+
+	return status;
+}
+
+/**
+ * wlan_serialization_generic_timer_callback() - timer callback when timer fire
+ * @arg: argument that timer passes to this callback
+ *
+ * All the timers in serialization module calls this callback when they fire,
+ * and this API in turn calls command specific timeout callback and remove
+ * timed-out command from active queue and move any pending command to active
+ * queue of same cmd_type.
+ *
+ * Return: none
+ */
+static void wlan_serialization_generic_timer_callback(void *arg)
+{
+	struct wlan_serialization_timer *timer = arg;
+	struct wlan_serialization_command *cmd = timer->cmd;
+
+	if (!cmd) {
+		serialization_err("command not found");
+		QDF_ASSERT(0);
+		return;
+	}
+	if (cmd->cmd_cb) {
+		cmd->cmd_cb(cmd->umac_cmd, WLAN_SER_CB_ACTIVE_CMD_TIMEOUT);
+		cmd->cmd_cb(cmd->umac_cmd, WLAN_SER_CB_RELEASE_MEM_CMD);
+	}
+	serialization_err("active command timeout for cmd_id[%d]", cmd->cmd_id);
+	if (cmd->cmd_type != WLAN_SER_CMD_SCAN)
+		QDF_BUG(0);
+	/*
+	 * dequeue cmd API will cleanup and destroy the timer. If it fails to
+	 * dequeue command then we have to destroy the timer.
+	 */
+	if (WLAN_SER_CMD_NOT_FOUND == wlan_serialization_dequeue_cmd(cmd, true))
+		wlan_serialization_timer_destroy(timer);
+}
+
+/**
+ * wlan_serialization_stop_timer() - to stop particular timer
+ * @ser_timer: pointer to serialization timer
+ *
+ * This API stops the particular timer
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+wlan_serialization_stop_timer(struct wlan_serialization_timer *ser_timer)
+{
+	QDF_TIMER_STATE state;
+	QDF_STATUS status;
+
+	state = qdf_mc_timer_get_current_state(&ser_timer->timer);
+	if (QDF_TIMER_STATE_RUNNING != state ||
+			QDF_TIMER_STATE_STARTING != state) {
+		serialization_debug("nothing to stop");
+		wlan_serialization_timer_destroy(ser_timer);
+		return QDF_STATUS_SUCCESS;
+	}
+	status = qdf_mc_timer_stop(&ser_timer->timer);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		serialization_err("Failed to stop timer");
+		/* to catch the bug */
+		QDF_ASSERT(0);
+		return status;
+	}
+	wlan_serialization_timer_destroy(ser_timer);
+	status = QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_serialization_cleanup_all_timers(
+			struct wlan_serialization_psoc_priv_obj *psoc_ser_obj)
+{
+	struct wlan_serialization_timer *ser_timer;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	uint32_t i = 0;
+
+	if (!psoc_ser_obj) {
+		serialization_err("Invalid psoc_ser_obj");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
+		ser_timer = &psoc_ser_obj->timers[i];
+		if (!ser_timer->cmd)
+			continue;
+		status = wlan_serialization_stop_timer(ser_timer);
+		if (QDF_STATUS_SUCCESS != status) {
+			/* lets not break the loop but report error */
+			serialization_err("some error in stopping timer");
+		}
+	}
+
+	return status;
+}
+
+QDF_STATUS
+wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc,
+				       struct wlan_serialization_command *cmd)
+{
+	struct wlan_serialization_psoc_priv_obj *psoc_ser_obj;
+	struct wlan_serialization_timer *ser_timer;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	int i = 0;
+
+	if (!psoc || !cmd) {
+		serialization_err("invalid param");
+		return status;
+	}
+
+	psoc_ser_obj = wlan_serialization_get_psoc_priv_obj(psoc);
+	/*
+	 * Here cmd_id and cmd_type are used to locate the timer being
+	 * associated with command. For scan command, cmd_id is expected to
+	 * be unique and For non-scan command, there should be only one active
+	 * command per pdev
+	 */
+	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
+		ser_timer = &psoc_ser_obj->timers[i];
+		if (!(ser_timer->cmd) ||
+				(ser_timer->cmd->cmd_id != cmd->cmd_id) ||
+				(ser_timer->cmd->cmd_type != cmd->cmd_type) ||
+				(ser_timer->cmd->vdev != cmd->vdev))
+			continue;
+		status = wlan_serialization_stop_timer(ser_timer);
+		if (QDF_STATUS_SUCCESS != status) {
+			serialization_err("Failed to stop timer for cmd_id[%d]",
+					cmd->cmd_id);
+		}
+		break;
+	}
+
+	if (QDF_STATUS_SUCCESS != status) {
+		serialization_err("can't find timer for cmd_type[%d]",
+				cmd->cmd_type);
+	}
+	return status;
+}
+
+QDF_STATUS
+wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc,
+					struct wlan_serialization_command *cmd)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct wlan_serialization_psoc_priv_obj *psoc_ser_obj;
+	struct wlan_serialization_timer *ser_timer;
+	int i = 0;
+
+	if (!psoc || !cmd) {
+		serialization_err("invalid param");
+		return status;
+	}
+
+	psoc_ser_obj = wlan_serialization_get_psoc_priv_obj(psoc);
+	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
+		/* Keep trying timer */
+		ser_timer = &psoc_ser_obj->timers[i];
+		if (ser_timer->cmd)
+			continue;
+		/* Remember timer is pointing to command */
+		ser_timer->cmd = cmd;
+		if (!QDF_IS_STATUS_SUCCESS(qdf_mc_timer_init(&ser_timer->timer,
+				QDF_TIMER_TYPE_SW,
+				wlan_serialization_generic_timer_callback,
+				ser_timer))) {
+			serialization_err("Failed to init timer cmdid [%d]",
+					cmd->cmd_id);
+			QDF_ASSERT(0);
+			continue;
+		}
+		if (!QDF_IS_STATUS_SUCCESS(qdf_mc_timer_start(&ser_timer->timer,
+						cmd->cmd_timeout_duration))) {
+			serialization_err("Failed to start timer cmdid [%d]",
+					cmd->cmd_id);
+			wlan_serialization_timer_destroy(ser_timer);
+			QDF_ASSERT(0);
+			continue;
+		}
+		status = QDF_STATUS_SUCCESS;
+		break;
+	}
+
+	return status;
+}
+
+/**
+ * wlan_serialization_active_scan_cmd_count_handler() - count active scan cmds
+ * @psoc: pointer to soc strucutre
+ * @obj : pointer to pdev object
+ * @arg: pointer to argument
+ *
+ * This API will be called while iterating each pdev object and it will count
+ * number of scan commands present in that pdev object's active queue. count
+ * will be updated in *arg
+ *
+ * Return: none
+ */
+static void
+wlan_serialization_active_scan_cmd_count_handler(struct wlan_objmgr_psoc *psoc,
+						 void *obj, void *arg)
+{
+	struct wlan_objmgr_pdev *pdev = obj;
+	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
+	uint32_t *count = arg;
+
+	if (!pdev) {
+		serialization_err("invalid pdev");
+		return;
+	}
+
+	ser_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(
+			pdev, WLAN_UMAC_COMP_SERIALIZATION);
+	*count += qdf_list_size(&ser_pdev_obj->active_scan_list);
+}
+
+/**
+ * wlan_serialization_is_active_scan_cmd_allowed() - find if scan cmd allowed
+ * @pdev: pointer to pdev object
+ *
+ * This API will be called to find out if active scan cmd is allowed. It has
+ * to iterate through all pdev to find out total number of active scan cmds.
+ * If total number of active scan cmds reach to allowed threshold then don't
+ * allow more scan cmd.
+ *
+ * Return: true or false
+ */
+static bool
+wlan_serialization_is_active_scan_cmd_allowed(struct wlan_objmgr_pdev *pdev)
+{
+	uint32_t count = 0;
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!pdev) {
+		serialization_err("invalid pdev");
+		return false;
+	}
+
+	psoc = wlan_pdev_get_psoc(pdev);
+
+	if (!psoc) {
+		serialization_err("invalid psoc");
+		return false;
+	}
+
+	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
+			wlan_serialization_active_scan_cmd_count_handler,
+			&count, 0);
+	if (count < WLAN_SERIALIZATION_MAX_ACTIVE_SCAN_CMDS) {
+		serialization_notice("count is [%d]", count);
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * wlan_serialization_is_active_nonscan_cmd_allowed() - find if cmd allowed
+ * @pdev: pointer to pdev object
+ *
+ * This API will be called to find out if non scan cmd is allowed.
+ *
+ * Return: true or false
+ */
+static bool
+wlan_serialization_is_active_nonscan_cmd_allowed(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
+
+	if (!pdev) {
+		serialization_err("invalid pdev");
+		return false;
+	}
+
+	ser_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(
+			pdev, WLAN_UMAC_COMP_SERIALIZATION);
+
+	if (!ser_pdev_obj) {
+		serialization_err("invalid ser_pdev_obj");
+		return false;
+	}
+
+	if (qdf_list_empty(&ser_pdev_obj->active_list))
+		return true;
+
+	return false;
+}
+
+bool
+wlan_serialization_is_active_cmd_allowed(struct wlan_serialization_command *cmd)
+{
+	struct wlan_objmgr_pdev *pdev;
+
+	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
+	if (!pdev) {
+		serialization_err("NULL pdev");
+		return false;
+	}
+
+	if (cmd->cmd_type == WLAN_SER_CMD_SCAN)
+		return wlan_serialization_is_active_scan_cmd_allowed(pdev);
+	else
+		return wlan_serialization_is_active_nonscan_cmd_allowed(pdev);
+}
 
 QDF_STATUS wlan_serialization_validate_cmd(
 		 enum wlan_umac_comp_id comp_id,

+ 197 - 19
umac/cmn_services/serialization/src/wlan_serialization_utils_i.h

@@ -25,33 +25,39 @@
 /* Include files */
 #include "qdf_status.h"
 #include "qdf_list.h"
+#include "qdf_mc_timer.h"
 #include "wlan_objmgr_cmn.h"
 #include "wlan_objmgr_global_obj.h"
 #include "wlan_objmgr_psoc_obj.h"
-#include "wlan_serialization_main_i.h"
 #include "wlan_serialization_rules_i.h"
 
 /**
- * struct wlan_serialization_psoc_priv_obj - psoc obj data for serialization
- * @wlan_serialization_module_state_cb - module level callback
- * @wlan_serialization_apply_rules_cb - pointer to apply rules on the cmd
- * @timers - Timers associated with the active commands
- * @max_axtive_cmds - Maximum active commands allowed
+ * struct wlan_serialization_timer - Timer used for serialization
+ * @cmd:      Cmd to which the timer is linked
+ * @timer:    Timer associated with the command
  *
- * Serialization component takes a command as input and checks whether to
- * allow/deny the command. It will use the module level callback registered
- * by each component to fetch the information needed to apply the rules.
- * Once the information is available, the rules callback registered for each
- * command internally by serialization will be applied to determine the
- * checkpoint for the command. If allowed, command will be put into active/
- * pending list and each active command is associated with a timer.
+ * Timers are allocated statically during init, one each for the
+ * maximum active commands permitted in the system. Once a cmd is
+ * moved from pending list to active list, the timer is activated
+ * and once the cmd is completed, the timer is cancelled. Timer is
+ * also cancelled if the command is aborted
+ *
+ * The timers are maintained per psoc. A timer is associated to
+ * unique combination of pdev, cmd_type and cmd_id.
  */
-struct wlan_serialization_psoc_priv_obj {
-	wlan_serialization_comp_info_cb comp_info_cb[
-		WLAN_SER_CMD_MAX][WLAN_UMAC_COMP_ID_MAX];
-	wlan_serialization_apply_rules_cb apply_rules_cb[WLAN_SER_CMD_MAX];
-	struct wlan_serialization_timer *timers;
-	uint8_t max_active_cmds;
+struct wlan_serialization_timer {
+	struct wlan_serialization_command *cmd;
+	qdf_mc_timer_t timer;
+};
+
+/**
+ * struct wlan_serialization_command_list - List of commands to be serialized
+ * @node: Node identifier in the list
+ * @cmd: Command to be serialized
+ */
+struct wlan_serialization_command_list {
+	qdf_list_node_t node;
+	struct wlan_serialization_command cmd;
 };
 
 /**
@@ -79,6 +85,178 @@ struct wlan_serialization_pdev_priv_obj {
 	qdf_list_t global_cmd_pool_list;
 };
 
+/**
+ * struct wlan_serialization_psoc_priv_obj - psoc obj data for serialization
+ * @wlan_serialization_module_state_cb - module level callback
+ * @wlan_serialization_apply_rules_cb - pointer to apply rules on the cmd
+ * @timers - Timers associated with the active commands
+ * @max_axtive_cmds - Maximum active commands allowed
+ *
+ * Serialization component takes a command as input and checks whether to
+ * allow/deny the command. It will use the module level callback registered
+ * by each component to fetch the information needed to apply the rules.
+ * Once the information is available, the rules callback registered for each
+ * command internally by serialization will be applied to determine the
+ * checkpoint for the command. If allowed, command will be put into active/
+ * pending list and each active command is associated with a timer.
+ */
+struct wlan_serialization_psoc_priv_obj {
+	wlan_serialization_comp_info_cb comp_info_cb[
+		WLAN_SER_CMD_MAX][WLAN_UMAC_COMP_ID_MAX];
+	wlan_serialization_apply_rules_cb apply_rules_cb[WLAN_SER_CMD_MAX];
+	struct wlan_serialization_timer *timers;
+	uint8_t max_active_cmds;
+};
+
+/**
+ * wlan_serialization_put_back_to_global_list() - put back cmd in global pool
+ * @queue: queue from which cmd needs to be taken out
+ * @ser_pdev_obj: pdev private object
+ * @cmd_list: cmd which needs to be matched
+ *
+ * command will be taken off from the queue and will be put back to global
+ * pool of free command buffers.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_serialization_put_back_to_global_list(qdf_list_t *queue,
+		struct wlan_serialization_pdev_priv_obj *ser_pdev_obj,
+		struct wlan_serialization_command_list *cmd_list);
+/**
+ * wlan_serialization_move_pending_to_active() - to move pending command to
+ *						 active queue
+ * @cmd_type: cmd type to device to which queue the command needs to go
+ * @ser_pdev_obj: pointer to ser_pdev_obj
+ *
+ * Return: none
+ */
+void wlan_serialization_move_pending_to_active(
+		enum wlan_serialization_cmd_type cmd_type,
+		struct wlan_serialization_pdev_priv_obj *ser_pdev_obj);
+/**
+ * wlan_serialization_get_pdev_from_cmd() - get pdev from provided cmd
+ * @cmd: pointer to actual command
+ *
+ * This API will get the pointer to pdev through checking type of cmd
+ *
+ * Return: pointer to pdev
+ */
+struct wlan_objmgr_pdev*
+wlan_serialization_get_pdev_from_cmd(struct wlan_serialization_command *cmd);
+
+/**
+ * wlan_serialization_get_cmd_from_queue() - to extract command from given queue
+ * @queue: pointer to queue
+ * @nnode: next node to extract
+ *
+ * This API will try to extract node from queue which is next to prev node. If
+ * no previous node is given then take out the front node of the queue.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_serialization_get_cmd_from_queue(qdf_list_t *queue,
+						 qdf_list_node_t **nnode);
+
+/**
+ * wlan_serialization_is_active_cmd_allowed() - check to see if command
+ *						is allowed in active queue
+ * @pdev: pointer to pdev structure
+ * @cmd_type: type of command to check against
+ *
+ * Takes the command type and based on the type, it checks scan command queue
+ * or nonscan command queue to see if active command is allowed or no
+ *
+ * Return: true if allowed else false
+ */
+bool wlan_serialization_is_active_cmd_allowed(
+			struct wlan_serialization_command *cmd);
+
+/**
+ * wlan_serialization_cleanup_all_timers() - to clean-up all timers
+ *
+ * @psoc_ser_ob: pointer to serialization psoc private object
+ *
+ * This API is to cleanup all the timers. it can be used when serialization
+ * module is exiting. it will make sure that if timer is running then it will
+ * stop and destroys the timer
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_serialization_cleanup_all_timers(
+	struct wlan_serialization_psoc_priv_obj *psoc_ser_ob);
+
+/**
+ * wlan_serialization_find_and_remove_cmd() - to find cmd from queue and remove
+ * @cmd_info: pointer to command related information
+ *
+ * This api will find command from active queue and removes the command
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_serialization_find_and_remove_cmd(
+		struct wlan_serialization_queued_cmd_info *cmd_info);
+
+/**
+ * wlan_serialization_find_and_cancel_cmd() - to find cmd from queue and cancel
+ * @cmd_info: pointer to command related information
+ *
+ * This api will find command from active queue and pending queue and
+ * removes the command. If it is in active queue then it will notifies the
+ * requester that it is in active queue and from there it expects requester
+ * to send remove command
+ *
+ * Return: wlan_serialization_cmd_status
+ */
+enum wlan_serialization_cmd_status
+wlan_serialization_find_and_cancel_cmd(
+		struct wlan_serialization_queued_cmd_info *cmd_info);
+/**
+ * wlan_serialization_enqueue_cmd() - Enqueue the cmd to pending/active Queue
+ * @cmd: Command information
+ * @is_cmd_for_active_queue: whether command is for active queue
+ *
+ * Return: Status of the serialization request
+ */
+enum wlan_serialization_status
+wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd,
+			       uint8_t is_cmd_for_active_queue);
+
+/**
+ * wlan_serialization_dequeue_cmd() - dequeue the cmd to pending/active Queue
+ * @cmd: Command information
+ * @is_cmd_for_active_queue: whether command is for active queue
+ *
+ * Return: Status of the serialization request
+ */
+enum wlan_serialization_cmd_status
+wlan_serialization_dequeue_cmd(struct wlan_serialization_command *cmd,
+			       uint8_t is_cmd_for_active_queue);
+/**
+ * wlan_serialization_find_and_stop_timer() - to find and stop the timer
+ * @psoc: pointer to psoc
+ * @cmd: pointer to actual command
+ *
+ * find the timer associated with command, stop it and destory it
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc,
+		struct wlan_serialization_command *cmd);
+/**
+ * wlan_serialization_find_and_stop_timer() - to find and start the timer
+ * @psoc: pointer to psoc
+ * @cmd: pointer to actual command
+ *
+ * find the free timer, initialize it, and start it
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc,
+		struct wlan_serialization_command *cmd);
+
 /**
  * wlan_serialization_validate_cmd() - Validate the command
  * @comp_id: Component ID