xref: /wlan-dirver/qca-wifi-host-cmn/utils/qld/src/qld.c (revision 503663c6daafffe652fa360bde17243568cd6d2a)
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