diff --git a/umac/cmn_services/serialization/inc/wlan_serialization_api.h b/umac/cmn_services/serialization/inc/wlan_serialization_api.h index 8cdb84c028..7abb44eeab 100644 --- a/umac/cmn_services/serialization/inc/wlan_serialization_api.h +++ b/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; diff --git a/umac/cmn_services/serialization/src/wlan_serialization_api.c b/umac/cmn_services/serialization/src/wlan_serialization_api.c index f056c35cc2..dc3b490662 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_api.c +++ b/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) { - serialization_info("serialization cancel request entry"); + QDF_STATUS status; - return WLAN_SER_CMD_NOT_FOUND; + 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_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) { - serialization_info("serialization queue cmd entry"); + bool is_active_cmd_allowed; + QDF_STATUS status; - return WLAN_SER_CMD_NOT_FOUND; + 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; + } + + 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; } diff --git a/umac/cmn_services/serialization/src/wlan_serialization_dequeue.c b/umac/cmn_services/serialization/src/wlan_serialization_dequeue.c index c1b01471c8..acc6acc770 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_dequeue.c +++ b/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 +#include "wlan_serialization_main_i.h" +#include "wlan_serialization_utils_i.h" +#include +#include +#include +#include + +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; +} diff --git a/umac/cmn_services/serialization/src/wlan_serialization_enqueue.c b/umac/cmn_services/serialization/src/wlan_serialization_enqueue.c index 55ee365b0a..64676b5a72 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_enqueue.c +++ b/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 +#include "wlan_serialization_main_i.h" +#include "wlan_serialization_utils_i.h" +#include +#include +#include +#include +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); +} diff --git a/umac/cmn_services/serialization/src/wlan_serialization_main.c b/umac/cmn_services/serialization/src/wlan_serialization_main.c index aaf3c63f25..da998e47f2 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_main.c +++ b/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); diff --git a/umac/cmn_services/serialization/src/wlan_serialization_main_i.h b/umac/cmn_services/serialization/src/wlan_serialization_main_i.h index 8cb199c219..853a65c572 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_main_i.h +++ b/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 diff --git a/umac/cmn_services/serialization/src/wlan_serialization_rules.c b/umac/cmn_services/serialization/src/wlan_serialization_rules.c index 67477e54b9..d708da6567 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_rules.c +++ b/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; diff --git a/umac/cmn_services/serialization/src/wlan_serialization_rules_i.h b/umac/cmn_services/serialization/src/wlan_serialization_rules_i.h index c2ff058681..ca3a287de1 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_rules_i.h +++ b/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 diff --git a/umac/cmn_services/serialization/src/wlan_serialization_utils.c b/umac/cmn_services/serialization/src/wlan_serialization_utils.c index 674789ae5f..2423616246 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_utils.c +++ b/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, diff --git a/umac/cmn_services/serialization/src/wlan_serialization_utils_i.h b/umac/cmn_services/serialization/src/wlan_serialization_utils_i.h index eeae06956b..4482198eeb 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_utils_i.h +++ b/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