diff --git a/umac/cmn_services/serialization/src/wlan_serialization_api.c b/umac/cmn_services/serialization/src/wlan_serialization_api.c index ceb0a9e693e2..646720a6ae4c 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_api.c +++ b/umac/cmn_services/serialization/src/wlan_serialization_api.c @@ -731,7 +731,7 @@ void wlan_serialization_remove_cmd( cmd.source = cmd_info->requestor; cmd.vdev = cmd_info->vdev; - if (wlan_serialization_dequeue_cmd(&cmd, true) != + if (wlan_serialization_dequeue_cmd(&cmd, SER_REMOVE, true) != WLAN_SER_CMD_IN_ACTIVE_LIST) { ser_err("Can't dequeue requested cmd_id[%d] type[%d]", cmd.cmd_id, cmd.cmd_type); @@ -792,7 +792,7 @@ wlan_serialization_request(struct wlan_serialization_command *cmd) return WLAN_SER_CMD_DENIED_RULES_FAILED; } - serialization_status = wlan_serialization_enqueue_cmd(cmd); + serialization_status = wlan_serialization_enqueue_cmd(cmd, SER_REQUEST); error: ser_exit(); diff --git a/umac/cmn_services/serialization/src/wlan_serialization_debug.c b/umac/cmn_services/serialization/src/wlan_serialization_debug.c new file mode 100644 index 000000000000..9cd4f31b97db --- /dev/null +++ b/umac/cmn_services/serialization/src/wlan_serialization_debug.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: wlan_serialization_debug.c + * This file defines the debug functions for serialization component. + */ + +#include +#include +#include +#include "wlan_serialization_utils_i.h" +#include "wlan_serialization_main_i.h" +#include "wlan_serialization_queue_i.h" +#include "wlan_serialization_debug_i.h" + +#ifdef WLAN_SER_DEBUG +const char *ser_reason_string[SER_QUEUE_ACTION_MAX] = { + "REQUEST", + "REMOVE", + "CANCEL", + "TIMEOUT", + "ACTIVATION_FAILED", + "PENDING_TO_ACTIVE", +}; + +static void wlan_ser_print_queues( + qdf_list_t *queue, + enum wlan_serialization_node node_type, + bool is_active_queue) +{ + struct wlan_serialization_command_list *cmd_list = NULL; + uint32_t queuelen; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + qdf_list_node_t *nnode = NULL; + bool is_pdev_queue = false; + + if (node_type == WLAN_SER_PDEV_NODE) + is_pdev_queue = true; + + ser_err(WLAN_SER_LINE); + ser_err("%s %s Queue", (is_pdev_queue) ? "PDEV" : "VDEV", + (is_active_queue ? "Active" : "Pending")); + + ser_err(WLAN_SER_LINE); + ser_err("|CMD_TYPE|CMD_ID|BLOCKING|PRIORITY|"); + ser_err(WLAN_SER_LINE); + + queuelen = wlan_serialization_list_size(queue); + while (queuelen--) { + status = wlan_serialization_get_cmd_from_queue(queue, &nnode); + if (status != QDF_STATUS_SUCCESS) + break; + + if (node_type == WLAN_SER_PDEV_NODE) + cmd_list = qdf_container_of( + nnode, + struct wlan_serialization_command_list, + pdev_node); + else + cmd_list = qdf_container_of( + nnode, + struct wlan_serialization_command_list, + vdev_node); + + ser_err("|%8u|%6u|%8u|%8u|", + cmd_list->cmd.cmd_type, + cmd_list->cmd.cmd_id, + cmd_list->cmd.is_blocking, + cmd_list->cmd.is_high_priority); + } +} + +static void wlan_ser_print_pdev_queue( + struct wlan_serialization_pdev_queue *ser_pdev_q_obj, + enum wlan_serialization_node node_type) +{ + /*Dump the active queue*/ + wlan_ser_print_queues(&ser_pdev_q_obj->active_list, + node_type, true); + + /*Dump the pending queue*/ + wlan_ser_print_queues(&ser_pdev_q_obj->pending_list, + node_type, false); +} + +static void wlan_ser_print_vdev_queue( + struct wlan_serialization_vdev_queue *ser_vdev_q_obj, + enum wlan_serialization_node node_type) +{ + /*Dump the active queue*/ + wlan_ser_print_queues(&ser_vdev_q_obj->active_list, + node_type, true); + + /*Dump the pending queue*/ + wlan_ser_print_queues(&ser_vdev_q_obj->pending_list, + node_type, false); +} + +static void wlan_ser_print_all_history( + struct wlan_serialization_pdev_queue *pdev_queue, + bool for_vdev_queue, + uint32_t vdev_id) +{ + uint8_t idx; + struct ser_history *history_info; + struct ser_data *data; + + history_info = &pdev_queue->history; + + if (!history_info->index) + return; + + ser_err(WLAN_SER_LINE WLAN_SER_LINE); + ser_err("Queue Commands History"); + ser_err(WLAN_SER_LINE WLAN_SER_LINE); + ser_err(WLAN_SER_HISTORY_HEADER); + ser_err(WLAN_SER_LINE WLAN_SER_LINE); + + for (idx = 0; idx < history_info->index; idx++) { + data = &history_info->data[idx]; + + if (data->ser_reason >= SER_QUEUE_ACTION_MAX) { + ser_err("Invalid Serialization Reason"); + continue; + } + + if (for_vdev_queue) { + if (vdev_id != data->vdev_id) + continue; + } + ser_err("%8d|%6d|%7d|%8d|%8d|%6s|%7s|%17s|", + data->cmd_type, + data->cmd_id, + data->vdev_id, + data->is_blocking, + data->is_high_priority, + data->add_remove ? "ADD" : "REMOVE", + data->active_pending ? "ACTIVE" : "PENDING", + ser_reason_string[data->ser_reason]); + } +} + +QDF_STATUS wlan_ser_print_history( + struct wlan_objmgr_vdev *vdev, uint8_t val, + uint32_t sub_val) +{ + struct wlan_ser_pdev_obj *ser_pdev; + struct wlan_ser_vdev_obj *ser_vdev; + struct wlan_serialization_pdev_queue *pdev_q; + struct wlan_serialization_vdev_queue *vdev_q; + bool for_vdev_queue = false; + uint32_t vdev_id; + + ser_pdev = wlan_serialization_get_pdev_obj( + wlan_vdev_get_pdev(vdev)); + + ser_vdev = wlan_serialization_get_vdev_obj(vdev); + + switch (val) { + /* + * Print scan pdev queues + */ + case SER_PDEV_QUEUE_COMP_SCAN: + ser_err("Serialization SCAN Queues(LIVE)"); + pdev_q = &ser_pdev->pdev_q[SER_PDEV_QUEUE_COMP_SCAN]; + wlan_ser_print_pdev_queue(pdev_q, WLAN_SER_PDEV_NODE); + break; + /* + * Print non scan queues + */ + case SER_PDEV_QUEUE_COMP_NON_SCAN: + pdev_q = &ser_pdev->pdev_q[SER_PDEV_QUEUE_COMP_NON_SCAN]; + ser_err("Serialization NON SCAN Queues(LIVE)"); + switch (sub_val) { + /* + * Print non scan pdev queues + */ + case SER_PDEV_QUEUE_TYPE: + wlan_ser_print_pdev_queue(pdev_q, WLAN_SER_PDEV_NODE); + break; + /* + * Print non scan pdev queues + */ + case SER_VDEV_QUEUE_TYPE: + vdev_q = + &ser_vdev->vdev_q[SER_VDEV_QUEUE_COMP_NON_SCAN]; + for_vdev_queue = true; + vdev_id = wlan_vdev_get_id(vdev); + wlan_ser_print_vdev_queue(vdev_q, WLAN_SER_VDEV_NODE); + break; + default: + ser_err("Invalid parameter for queue type(pdev/vdev)"); + } + break; + default: + ser_err("Invalid pramater for queue type(scan/non_scan"); + goto error; + } + + wlan_ser_print_all_history(pdev_q, for_vdev_queue, vdev_id); +error: + return QDF_STATUS_SUCCESS; +} + +void wlan_ser_update_cmd_history( + struct wlan_serialization_pdev_queue *pdev_queue, + struct wlan_serialization_command *cmd, + enum ser_queue_reason ser_reason, + bool add_remove, + bool active_queue) +{ + struct ser_data *ser_data_info; + struct ser_history *ser_history_info; + + ser_history_info = &pdev_queue->history; + ser_history_info->index %= SER_MAX_HISTORY_CMDS; + + ser_data_info = &ser_history_info->data[ser_history_info->index]; + + ser_data_info->cmd_type = cmd->cmd_type; + ser_data_info->cmd_id = cmd->cmd_id; + ser_data_info->is_blocking = cmd->is_blocking; + ser_data_info->is_high_priority = cmd->is_high_priority; + ser_data_info->add_remove = add_remove; + ser_data_info->active_pending = active_queue; + ser_data_info->ser_reason = ser_reason; + ser_data_info->vdev_id = wlan_vdev_get_id(cmd->vdev); + + ser_history_info->index++; +} +#endif diff --git a/umac/cmn_services/serialization/src/wlan_serialization_debug_i.h b/umac/cmn_services/serialization/src/wlan_serialization_debug_i.h new file mode 100644 index 000000000000..9705272b4a02 --- /dev/null +++ b/umac/cmn_services/serialization/src/wlan_serialization_debug_i.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: wlan_serialization_debug_i.h + * This file defines the prototypes for the debug functions + * for the serialization component. + */ + +#ifndef __WLAN_SERIALIZATION_DEBUG_I_H +#define __WLAN_SERIALIZATION_DEBUG_I_H + +#ifdef WLAN_SER_DEBUG + +#define SER_MAX_HISTORY_CMDS 50 + +#define WLAN_SER_LINE "--------------------"\ + "--------------------" + +#define WLAN_SER_HISTORY_HEADER "CMD_TYPE|CMD_ID|VDEV_ID|"\ + "BLOCKING|PRIORITY|ACTION|"\ + " QUEUE| REASON|" + +enum ser_queue_type { + SER_PDEV_QUEUE_TYPE, + SER_VDEV_QUEUE_TYPE, +}; + +struct ser_data { + /* + * Serialization Actions that modifies the serialization queues + * 0: SER_REQUEST + * 1: SER_REMOVE + * 2: SER_CANCEL + * 3: SER_TIMEOUT + * 4: SER_ACTIVATION_FAILED + * 5: SER_PENDING_TO_ACTIVE + */ + uint32_t cmd_type:6, /* max 2^6 = 64 types of commands */ + cmd_id:16, /* max cmd_id = 2^16 */ + is_blocking:1, + is_high_priority:1, + add_remove:1, + active_pending:1, + ser_reason:6; + + uint16_t vdev_id; +}; + +struct ser_history { + struct ser_data data[SER_MAX_HISTORY_CMDS]; + uint16_t index; +}; +#endif /* WLAN_SER_DEBUG */ +#endif + diff --git a/umac/cmn_services/serialization/src/wlan_serialization_internal.c b/umac/cmn_services/serialization/src/wlan_serialization_internal.c index d2f697336e53..512884f8da6d 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_internal.c +++ b/umac/cmn_services/serialization/src/wlan_serialization_internal.c @@ -86,7 +86,8 @@ error: } enum wlan_serialization_status -wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd) +wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd, + enum ser_queue_reason ser_reason) { enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED; struct wlan_serialization_command_list *cmd_list; @@ -204,12 +205,14 @@ wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd) } if (status != WLAN_SER_CMD_PENDING && status != WLAN_SER_CMD_ACTIVE) { - ser_err("Failed to add cmd to active/pending queue"); qdf_mem_zero(&cmd_list->cmd, sizeof(struct wlan_serialization_command)); wlan_serialization_insert_back( &pdev_queue->cmd_pool_list, &cmd_list->pdev_node); + wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); + ser_err("Failed to add cmd to active/pending queue"); + goto error; } if (WLAN_SER_CMD_ACTIVE == status) { @@ -217,6 +220,9 @@ wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd) &cmd_list->cmd_in_use); } + wlan_ser_update_cmd_history(pdev_queue, &cmd_list->cmd, + ser_reason, true, active_queue); + wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); if (WLAN_SER_CMD_ACTIVE == status) @@ -277,7 +283,9 @@ QDF_STATUS wlan_serialization_activate_cmd( wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); if (QDF_IS_STATUS_ERROR(status)) { - wlan_serialization_dequeue_cmd(&cmd_list->cmd, true); + wlan_serialization_dequeue_cmd(&cmd_list->cmd, + SER_ACTIVATION_FAILED, + true); return status; } @@ -350,6 +358,7 @@ wlan_serialization_move_pending_to_active( enum wlan_serialization_cmd_status wlan_serialization_dequeue_cmd(struct wlan_serialization_command *cmd, + enum ser_queue_reason ser_reason, uint8_t active_cmd) { enum wlan_serialization_cmd_status status = @@ -432,6 +441,9 @@ wlan_serialization_dequeue_cmd(struct wlan_serialization_command *cmd, &pdev_queue->cmd_pool_list, &cmd_list->pdev_node); + wlan_ser_update_cmd_history(pdev_queue, &cmd_bkup, ser_reason, + false, active_cmd); + wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); /* Call cmd cb for remove request*/ @@ -483,7 +495,7 @@ void wlan_serialization_generic_timer_cb(void *arg) * dequeue cmd API will cleanup and destroy the timer. If it fails to * dequeue command then we have to destroy the timer. */ - wlan_serialization_dequeue_cmd(cmd, true); + wlan_serialization_dequeue_cmd(cmd, SER_TIMEOUT, true); } static QDF_STATUS wlan_serialization_mc_flush_noop(struct scheduler_msg *msg) diff --git a/umac/cmn_services/serialization/src/wlan_serialization_internal_i.h b/umac/cmn_services/serialization/src/wlan_serialization_internal_i.h index f234e3cf058d..9f94d947f587 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_internal_i.h +++ b/umac/cmn_services/serialization/src/wlan_serialization_internal_i.h @@ -65,11 +65,13 @@ wlan_serialization_is_active_cmd_allowed( /** * wlan_serialization_enqueue_cmd() - Enqueue the cmd to pending/active Queue * @cmd: Command information + * @ser_reason: action for dequeue * * Return: Status of the serialization request */ enum wlan_serialization_status -wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd); +wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd, + enum ser_queue_reason ser_reason); /** * wlan_serialization_activate_cmd() - activate cmd in active queue @@ -105,12 +107,14 @@ wlan_serialization_move_pending_to_active( /** * wlan_serialization_dequeue_cmd() - dequeue the cmd to pending/active Queue * @cmd: Command information + * @ser_reason: action for dequeue * @active_cmd: 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, + enum ser_queue_reason ser_reason, uint8_t active_cmd); /** diff --git a/umac/cmn_services/serialization/src/wlan_serialization_non_scan.c b/umac/cmn_services/serialization/src/wlan_serialization_non_scan.c index 1844b6f4c656..e18065fdb133 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_non_scan.c +++ b/umac/cmn_services/serialization/src/wlan_serialization_non_scan.c @@ -289,6 +289,11 @@ wlan_ser_move_non_scan_pending_to_active( &cmd_to_remove, false); + wlan_ser_update_cmd_history( + pdev_queue, &pending_cmd_list->cmd, + SER_PENDING_TO_ACTIVE, + false, false); + if (QDF_STATUS_SUCCESS != qdf_status) { wlan_serialization_release_lock( &pdev_queue->pdev_queue_lock); @@ -318,6 +323,11 @@ wlan_ser_move_non_scan_pending_to_active( goto error; } + wlan_ser_update_cmd_history( + pdev_queue, &active_cmd_list->cmd, + SER_PENDING_TO_ACTIVE, + true, true); + qdf_atomic_set_bit(CMD_MARKED_FOR_ACTIVATION, &active_cmd_list->cmd_in_use); @@ -550,6 +560,9 @@ wlan_ser_cancel_non_scan_cmd( } nnode = pnode; + wlan_ser_update_cmd_history(pdev_q, &cmd_bkup, + SER_CANCEL, false, is_active_queue); + wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); /* * call pending cmd's callback to notify that diff --git a/umac/cmn_services/serialization/src/wlan_serialization_scan.c b/umac/cmn_services/serialization/src/wlan_serialization_scan.c index 006c8a814d91..54fbd5fb9d4d 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_scan.c +++ b/umac/cmn_services/serialization/src/wlan_serialization_scan.c @@ -286,6 +286,9 @@ wlan_ser_cancel_scan_cmd( } nnode = pnode; + wlan_ser_update_cmd_history(pdev_q, &cmd_bkup, + SER_CANCEL, false, is_active_queue); + wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); /* * call pending cmd's callback to notify that @@ -374,6 +377,10 @@ enum wlan_serialization_status wlan_ser_move_scan_pending_to_active( &pending_cmd_list, &cmd_to_remove, false); + wlan_ser_update_cmd_history(pdev_queue, &pending_cmd_list->cmd, + SER_PENDING_TO_ACTIVE, + false, false); + if (QDF_STATUS_SUCCESS != qdf_status) { wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); ser_err("Can't remove cmd from pendingQ id-%d type-%d", @@ -405,6 +412,10 @@ enum wlan_serialization_status wlan_ser_move_scan_pending_to_active( qdf_atomic_set_bit(CMD_MARKED_FOR_ACTIVATION, &active_cmd_list->cmd_in_use); + wlan_ser_update_cmd_history(pdev_queue, &active_cmd_list->cmd, + SER_PENDING_TO_ACTIVE, + true, true); + wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); wlan_serialization_activate_cmd(active_cmd_list, ser_pdev_obj); diff --git a/umac/cmn_services/serialization/src/wlan_serialization_utils.c b/umac/cmn_services/serialization/src/wlan_serialization_utils.c index 8e8d05e55790..829ee3b84435 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_utils.c +++ b/umac/cmn_services/serialization/src/wlan_serialization_utils.c @@ -1004,6 +1004,15 @@ wlan_serialization_destroy_lock(struct wlan_serialization_pdev_priv_obj *obj) #include "wlan_serialization_queue_i.h" #include "wlan_serialization_api.h" +#ifndef WLAN_SER_DEBUG +void wlan_ser_update_cmd_history( + struct wlan_serialization_pdev_queue *pdev_queue, + struct wlan_serialization_command *cmd, + enum ser_queue_reason ser_reason, + bool add_remove, + bool active_queue){ } +#endif + struct wlan_objmgr_pdev* wlan_serialization_get_pdev_from_cmd(struct wlan_serialization_command *cmd) { 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 cc6729365800..dc76e5d598e5 100644 --- a/umac/cmn_services/serialization/src/wlan_serialization_utils_i.h +++ b/umac/cmn_services/serialization/src/wlan_serialization_utils_i.h @@ -625,6 +625,19 @@ QDF_STATUS wlan_serialization_peek_next( #include #include #include "wlan_serialization_rules_i.h" +#ifdef WLAN_SER_DEBUG +#include "wlan_serialization_debug_i.h" +#endif + +enum ser_queue_reason { + SER_REQUEST, + SER_REMOVE, + SER_CANCEL, + SER_TIMEOUT, + SER_ACTIVATION_FAILED, + SER_PENDING_TO_ACTIVE, + SER_QUEUE_ACTION_MAX, +}; /* * Below bit positions are used to identify if a @@ -697,6 +710,9 @@ struct wlan_serialization_pdev_queue { bool blocking_cmd_active; uint16_t blocking_cmd_waiting; qdf_spinlock_t pdev_queue_lock; +#ifdef WLAN_SER_DEBUG + struct ser_history history; +#endif }; /** @@ -1237,5 +1253,24 @@ wlan_serialization_create_lock(qdf_spinlock_t *lock); */ QDF_STATUS wlan_serialization_destroy_lock(qdf_spinlock_t *lock); + +/** + * wlan_ser_update_cmd_history() - Update serialization queue history + * @pdev_queue:serialization pdev queue + * @cmd: cmd to be added/remeoved + * @ser_reason: serialization action that resulted in addition/removal + * @add_remove: added or removed from queue + * @active_queue:for active queue + * + * Return: QDF_STATUS success or failure + */ + +void wlan_ser_update_cmd_history( + struct wlan_serialization_pdev_queue *pdev_queue, + struct wlan_serialization_command *cmd, + enum ser_queue_reason ser_reason, + bool add_remove, + bool active_queue); + #endif #endif