diff --git a/qdf/inc/qdf_types.h b/qdf/inc/qdf_types.h index bc43c990dcfe..26ea31ec1257 100644 --- a/qdf/inc/qdf_types.h +++ b/qdf/inc/qdf_types.h @@ -372,6 +372,7 @@ typedef bool (*qdf_irqlocked_func_t)(void *); * @QDF_MODULE_ID_TX_CAPTURE: Tx capture enhancement feature ID * @QDF_MODULE_ID_INTEROP_ISSUES_AP: interop issues ap module ID * @QDF_MODULE_ID_BLACKLIST_MGR: Blacklist Manager module + * @QDF_MODULE_ID_QLD: QCA Live Debug module ID * @QDF_MODULE_ID_ANY: anything * @QDF_MODULE_ID_MAX: Max place holder module ID */ @@ -488,6 +489,7 @@ typedef enum { QDF_MODULE_ID_TX_CAPTURE, QDF_MODULE_ID_INTEROP_ISSUES_AP, QDF_MODULE_ID_BLACKLIST_MGR, + QDF_MODULE_ID_QLD, QDF_MODULE_ID_ANY, QDF_MODULE_ID_MAX, } QDF_MODULE_ID; diff --git a/qdf/linux/src/qdf_trace.c b/qdf/linux/src/qdf_trace.c index b2f7e98ae328..99150ebd19cf 100644 --- a/qdf/linux/src/qdf_trace.c +++ b/qdf/linux/src/qdf_trace.c @@ -2710,6 +2710,7 @@ struct category_name_info g_qdf_category_name[MAX_SUPPORTED_CATEGORY] = { [QDF_MODULE_ID_TX_CAPTURE] = {"TX_CAPTURE_ENHANCE"}, [QDF_MODULE_ID_INTEROP_ISSUES_AP] = {"INTEROP_ISSUES_AP"}, [QDF_MODULE_ID_BLACKLIST_MGR] = {"blm"}, + [QDF_MODULE_ID_QLD] = {"QLD"}, [QDF_MODULE_ID_ANY] = {"ANY"}, }; qdf_export_symbol(g_qdf_category_name); @@ -3168,6 +3169,7 @@ static void set_default_trace_levels(struct category_info *cinfo) [QDF_MODULE_ID_TX_CAPTURE] = QDF_TRACE_LEVEL_NONE, [QDF_MODULE_ID_INTEROP_ISSUES_AP] = QDF_TRACE_LEVEL_NONE, [QDF_MODULE_ID_BLACKLIST_MGR] = QDF_TRACE_LEVEL_NONE, + [QDF_MODULE_ID_QLD] = QDF_TRACE_LEVEL_ERROR, [QDF_MODULE_ID_ANY] = QDF_TRACE_LEVEL_INFO, }; diff --git a/utils/qld/inc/qld_api.h b/utils/qld/inc/qld_api.h new file mode 100644 index 000000000000..9afdf28ebe27 --- /dev/null +++ b/utils/qld/inc/qld_api.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2019 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: qld_api.h + * QLD: This file provides public exposed functions + */ + +#ifndef _QLD_API_H_ +#define _QLD_API_H_ + +#define QLD_MAX_NAME 48 + +/** + * struct qld_entry - Individual entry in qld_event + * @addr: Start address of object to dump + * @size: Size of memory dump + * @name: Name of memory dump + */ +struct qld_entry { + uint64_t addr; + size_t size; + char name[QLD_MAX_NAME]; +}; + +/** + * typedef qld_iter_func - qld callback function + * @req: opaque pointer + * @qld_entry: qld_entry + * + * Return: 0 - OK -EINVAL - On failure + */ +typedef int (*qld_iter_func)(void *req, struct qld_entry *entry); + +/** + * qld_iterate_list() - qld list iteration routine + * @gen_table: callback function to genrate table + * @req: opaque request + * + * Return: 0 - OK -EINVAL - On failure + */ +int qld_iterate_list(qld_iter_func gen_table, void *req); + +/** + * qld_register() - Register qld for the given address + * @addr: starting address the dump + * @size: size of memory to dump + * @name: name identifier of dump + * + * Return: 0 - OK -EINVAL -ENOMEM - On failure + */ +int qld_register(void *addr, size_t size, char *name); + +/** + * qld_unregister() - Un-register qld for the given address + * @addr: starting address the dump + * + * Return: 0 - OK -EINVAL - On failure + */ +int qld_unregister(void *addr); + +/** + * qld_list_init() - Initialize qld list + * @max_list: maximum size list supports + * + * Return: 0 - OK -EINVAL -ENOMEM - On failure + */ +int qld_list_init(uint32_t max_list); + +/** + * qld_list_delete() - empty qld list + * + * Return: 0 - OK -EINVAL - On failure + */ +int qld_list_delete(void); + +/** + * qld_list_deinit() - De-initialize qld list + * + * Return: 0 - OK -EINVAL - On failure + */ +int qld_list_deinit(void); + +/** + * qld_get_list_count () - get size of qld list + * @list_count: list_count to set + * + * Return: 0 - OK -EINVAL - On failure + */ +int qld_get_list_count(uint32_t *list_count); + +/** + * is_qld_enable() - check if qld feature is set + * + * Return: true on success, false on failure + */ +bool is_qld_enable(void); + +#endif /* _QLD_API_H_ */ diff --git a/utils/qld/inc/qld_priv.h b/utils/qld/inc/qld_priv.h new file mode 100644 index 000000000000..ebf7b56931a8 --- /dev/null +++ b/utils/qld/inc/qld_priv.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 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: qld_priv.h + * QLD: This file provies Private functions for qld + */ + +#ifndef _QLD_PRIV_H_ +#define _QLD_PRIV_H_ + +#include +#include +#include + +#define qld_alert(format, args...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_QLD, format, ## args) + +#define qld_err(format, args...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_QLD, format, ## args) + +#define qld_warn(format, args...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_QLD, format, ## args) + +#define qld_info(format, args...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_QLD, format, ## args) + +#define qld_debug(format, args...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_QLD, format, ## args) + +/** + * struct qld_list_handle - Top level qld structure + * @qld_lock: Spinlock for structure + * @qld_list: linked list for linking + * @qld_max_list: maximum list size + */ +struct qld_list_handle { + qdf_spinlock_t qld_lock; + qdf_list_t qld_list; + uint32_t qld_max_list; +}; + +/** + * struct qld_node - qld node + * @node: single node of linked list + * @entry: single qld_entry in list + */ +struct qld_node { + qdf_list_node_t node; + struct qld_entry entry; +}; + +#endif /*_QLD_PRIV_H_*/ diff --git a/utils/qld/src/qld.c b/utils/qld/src/qld.c new file mode 100644 index 000000000000..d377d59a89dc --- /dev/null +++ b/utils/qld/src/qld.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2019 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: qld + * QLD: main file of QCA Live Dump (QLD) + */ + +#include "qld_priv.h" +#include "qld_api.h" +#include "qdf_module.h" + +/* Handle for qld structure */ +static struct qld_list_handle *qld_handle; + +bool is_qld_enable(void) +{ + if (!qld_handle) + return false; + + return true; +} + +qdf_export_symbol(is_qld_enable); + +int qld_list_init(uint32_t max_list) +{ + if (!max_list) + return -EINVAL; + + qld_handle = qdf_mem_malloc(sizeof(*qld_handle)); + + if (!qld_handle) + return -ENOMEM; + + qdf_spinlock_create(&qld_handle->qld_lock); + qld_handle->qld_max_list = max_list; + qdf_list_create(&qld_handle->qld_list, qld_handle->qld_max_list); + qld_debug("LIST init with max size of %u", qld_handle->qld_max_list); + return 0; +} + +qdf_export_symbol(qld_list_init); + +int qld_list_deinit(void) +{ + if (!qld_handle) { + qld_err("Handle NULL"); + return -EINVAL; + } + /* Delete the list */ + qld_list_delete(); + qdf_list_destroy(&qld_handle->qld_list); + qdf_spinlock_destroy(&qld_handle->qld_lock); + qdf_mem_free(qld_handle); + qld_handle = NULL; + qld_debug("LIST De-initialized"); + return 0; +} + +qdf_export_symbol(qld_list_deinit); + +int qld_list_delete(void) +{ + struct qld_node *qld; + qdf_list_node_t *node = NULL; + qdf_list_t *list; + + if (!qld_handle) { + qld_err("Handle NULL"); + return -EINVAL; + } + list = &qld_handle->qld_list; + qdf_spinlock_acquire(&qld_handle->qld_lock); + /* Check and remove the elements of list */ + while (qdf_list_remove_front(list, &node) == QDF_STATUS_SUCCESS) { + qld = qdf_container_of(node, struct qld_node, node); + qdf_mem_free(qld); + } + qdf_spinlock_release(&qld_handle->qld_lock); + qld_debug("LIST Emptied"); + return 0; +} + +qdf_export_symbol(qld_list_delete); + +int qld_register(void *addr, size_t size, char *name) +{ + struct qld_node *qld; + uint32_t list_count = 0; + + if (!qld_handle || !addr) { + qld_err("Handle or address is NULL"); + return -EINVAL; + } + + if ((qld_get_list_count(&list_count) != 0)) { + qdf_err("QLD: Invalid list count"); + return -EINVAL; + } + if (list_count >= qld_handle->qld_max_list) { + qld_err("List full,reg failed.Increase list size"); + return -EINVAL; + } + /* Check if data is already registered */ + qdf_spinlock_acquire(&qld_handle->qld_lock); + qdf_list_for_each(&qld_handle->qld_list, qld, node) { + if (qld->entry.addr == (uintptr_t)addr) { + qld_err("%s already registered", qld->entry.name); + qdf_spinlock_release(&qld_handle->qld_lock); + return -EINVAL; + } + } + qdf_spinlock_release(&qld_handle->qld_lock); + qld = qdf_mem_malloc(sizeof(*qld)); + if (!qld) + return -ENOMEM; + + qld_debug("Insert addr=%pK size=%zu name=%s", (void *)addr, size, name); + qdf_spinlock_acquire(&qld_handle->qld_lock); + qld->entry.addr = (uintptr_t)addr; + qld->entry.size = size; + qdf_snprintf(qld->entry.name, sizeof(qld->entry.name), "%s", name); + qdf_list_insert_front(&qld_handle->qld_list, &qld->node); + qdf_spinlock_release(&qld_handle->qld_lock); + return 0; +} + +qdf_export_symbol(qld_register); + +int qld_unregister(void *addr) +{ + struct qld_node *qld = NULL; + + if (!qld_handle || !addr) { + qld_err("Handle or address is NULL"); + return -EINVAL; + } + + qdf_spinlock_acquire(&qld_handle->qld_lock); + qdf_list_for_each(&qld_handle->qld_list, qld, node) { + if (qld->entry.addr == (uintptr_t)addr) + break; + } + qdf_list_remove_node(&qld_handle->qld_list, &qld->node); + qld_debug("Delete name=%s, size=%zu", qld->entry.name, qld->entry.size); + qdf_mem_free(qld); + qdf_spinlock_release(&qld_handle->qld_lock); + return 0; +} + +qdf_export_symbol(qld_unregister); + +int qld_iterate_list(qld_iter_func gen_table, void *qld_req) +{ + struct qld_node *qld = NULL; + + if (!qld_handle) + return -EINVAL; + + if (!qld_req || !gen_table) { + qld_err("req buffer or func is NULL %s", __func__); + return -EINVAL; + } + qdf_spinlock_acquire(&qld_handle->qld_lock); + qdf_list_for_each(&qld_handle->qld_list, qld, node) { + (gen_table)(qld_req, &qld->entry); + } + qdf_spinlock_release(&qld_handle->qld_lock); + return 0; +} + +qdf_export_symbol(qld_iterate_list); + +int qld_get_list_count(uint32_t *list_count) +{ + if (!qld_handle) { + qld_err("Handle NULL"); + return -EINVAL; + } + *list_count = qld_handle->qld_list.count; + return 0; +} + +qdf_export_symbol(qld_get_list_count);