1 /* 2 * Copyright (c) 2019 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: qld 22 * QLD: main file of QCA Live Dump (QLD) 23 */ 24 25 #include "qld_priv.h" 26 #include "qld_api.h" 27 #include "qdf_module.h" 28 29 /* Handle for qld structure */ 30 static struct qld_list_handle *qld_handle; 31 32 bool is_qld_enable(void) 33 { 34 if (!qld_handle) 35 return false; 36 37 return true; 38 } 39 40 qdf_export_symbol(is_qld_enable); 41 42 int qld_list_init(uint32_t max_list) 43 { 44 if (!max_list) 45 return -EINVAL; 46 47 qld_handle = qdf_mem_malloc(sizeof(*qld_handle)); 48 49 if (!qld_handle) 50 return -ENOMEM; 51 52 qdf_spinlock_create(&qld_handle->qld_lock); 53 qld_handle->qld_max_list = max_list; 54 qdf_list_create(&qld_handle->qld_list, qld_handle->qld_max_list); 55 qld_debug("LIST init with max size of %u", qld_handle->qld_max_list); 56 return 0; 57 } 58 59 qdf_export_symbol(qld_list_init); 60 61 int qld_list_deinit(void) 62 { 63 if (!qld_handle) { 64 qld_err("Handle NULL"); 65 return -EINVAL; 66 } 67 /* Delete the list */ 68 qld_list_delete(); 69 qdf_list_destroy(&qld_handle->qld_list); 70 qdf_spinlock_destroy(&qld_handle->qld_lock); 71 qdf_mem_free(qld_handle); 72 qld_handle = NULL; 73 qld_debug("LIST De-initialized"); 74 return 0; 75 } 76 77 qdf_export_symbol(qld_list_deinit); 78 79 int qld_list_delete(void) 80 { 81 struct qld_node *qld; 82 qdf_list_node_t *node = NULL; 83 qdf_list_t *list; 84 85 if (!qld_handle) { 86 qld_err("Handle NULL"); 87 return -EINVAL; 88 } 89 list = &qld_handle->qld_list; 90 qdf_spinlock_acquire(&qld_handle->qld_lock); 91 /* Check and remove the elements of list */ 92 while (qdf_list_remove_front(list, &node) == QDF_STATUS_SUCCESS) { 93 qld = qdf_container_of(node, struct qld_node, node); 94 qdf_mem_free(qld); 95 } 96 qdf_spinlock_release(&qld_handle->qld_lock); 97 qld_debug("LIST Emptied"); 98 return 0; 99 } 100 101 qdf_export_symbol(qld_list_delete); 102 103 int qld_register(void *addr, size_t size, char *name) 104 { 105 struct qld_node *qld; 106 uint32_t list_count = 0; 107 108 if (!qld_handle || !addr) { 109 qld_debug("Handle or address is NULL"); 110 return -EINVAL; 111 } 112 113 if ((qld_get_list_count(&list_count) != 0)) { 114 qdf_err("QLD: Invalid list count"); 115 return -EINVAL; 116 } 117 if (list_count >= qld_handle->qld_max_list) { 118 qld_err("List full,reg failed.Increase list size"); 119 return -EINVAL; 120 } 121 /* Check if data is already registered */ 122 qdf_spinlock_acquire(&qld_handle->qld_lock); 123 qdf_list_for_each(&qld_handle->qld_list, qld, node) { 124 if (qld->entry.addr == (uintptr_t)addr) { 125 qld_err("%s already registered", qld->entry.name); 126 qdf_spinlock_release(&qld_handle->qld_lock); 127 return -EINVAL; 128 } 129 } 130 qdf_spinlock_release(&qld_handle->qld_lock); 131 qld = qdf_mem_malloc(sizeof(*qld)); 132 if (!qld) 133 return -ENOMEM; 134 135 qld_debug("Insert addr=%pK size=%zu name=%s", (void *)addr, size, name); 136 qdf_spinlock_acquire(&qld_handle->qld_lock); 137 qld->entry.addr = (uintptr_t)addr; 138 qld->entry.size = size; 139 qdf_snprintf(qld->entry.name, sizeof(qld->entry.name), "%s", name); 140 qdf_list_insert_front(&qld_handle->qld_list, &qld->node); 141 qdf_spinlock_release(&qld_handle->qld_lock); 142 return 0; 143 } 144 145 qdf_export_symbol(qld_register); 146 147 int qld_unregister(void *addr) 148 { 149 struct qld_node *qld = NULL; 150 struct qld_node *cur_entry; 151 152 if (!qld_handle || !addr) { 153 qld_err("Handle or address is NULL"); 154 return -EINVAL; 155 } 156 qdf_spinlock_acquire(&qld_handle->qld_lock); 157 qdf_list_for_each(&qld_handle->qld_list, cur_entry, node) { 158 if (cur_entry->entry.addr == (uintptr_t)addr) { 159 qld = cur_entry; 160 break; 161 } 162 } 163 164 if (qld) { 165 qdf_list_remove_node(&qld_handle->qld_list, &qld->node); 166 qld_debug("Delete name=%s, size=%zu", qld->entry.name, 167 qld->entry.size); 168 qdf_mem_free(qld); 169 } 170 qdf_spinlock_release(&qld_handle->qld_lock); 171 return 0; 172 } 173 174 qdf_export_symbol(qld_unregister); 175 176 int qld_iterate_list(qld_iter_func gen_table, void *qld_req) 177 { 178 struct qld_node *qld = NULL; 179 180 if (!qld_handle) 181 return -EINVAL; 182 183 if (!qld_req || !gen_table) { 184 qld_err("req buffer or func is NULL %s", __func__); 185 return -EINVAL; 186 } 187 qdf_spinlock_acquire(&qld_handle->qld_lock); 188 qdf_list_for_each(&qld_handle->qld_list, qld, node) { 189 (gen_table)(qld_req, &qld->entry); 190 } 191 qdf_spinlock_release(&qld_handle->qld_lock); 192 return 0; 193 } 194 195 qdf_export_symbol(qld_iterate_list); 196 197 int qld_get_list_count(uint32_t *list_count) 198 { 199 if (!qld_handle) { 200 qld_err("Handle NULL"); 201 return -EINVAL; 202 } 203 *list_count = qld_handle->qld_list.count; 204 return 0; 205 } 206 207 qdf_export_symbol(qld_get_list_count); 208