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
此提交包含在:
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
新增問題並參考
封鎖使用者