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