1 /*
2  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "qdf_ssr_driver_dump.h"
18 #include "qdf_lock.h"
19 #include "qdf_str.h"
20 #include <qdf_trace.h>
21 #include <qdf_parse.h>
22 #include <qdf_module.h>
23 #include <qdf_util.h>
24 #include <qdf_mem.h>
25 #include <qdf_types.h>
26 
27 static qdf_mutex_t region_list_mutex;
28 
29 static struct cnss_ssr_driver_dump_entry
30 dump_entry_list[CNSS_HOST_DUMP_TYPE_MAX];
31 
32 static size_t num_of_regions_registered;
33 
qdf_ssr_driver_dump_init(void)34 QDF_STATUS qdf_ssr_driver_dump_init(void)
35 {
36 	QDF_STATUS status;
37 
38 	status = qdf_mutex_create(&region_list_mutex);
39 	if (QDF_IS_STATUS_ERROR(status))
40 		return status;
41 
42 	num_of_regions_registered = 0;
43 	qdf_mem_zero(dump_entry_list, sizeof(dump_entry_list));
44 	return status;
45 }
46 
qdf_ssr_driver_dump_deinit(void)47 QDF_STATUS qdf_ssr_driver_dump_deinit(void)
48 {
49 	QDF_STATUS status;
50 
51 	status = qdf_mutex_destroy(&region_list_mutex);
52 	if (QDF_IS_STATUS_ERROR(status))
53 		return status;
54 	if (num_of_regions_registered > 0)
55 		qdf_warn("deiniting with regions still registered");
56 	num_of_regions_registered = 0;
57 	return status;
58 }
59 
60 static struct cnss_ssr_driver_dump_entry *
qdf_ssr_driver_dump_find_next_free_entry(void)61 qdf_ssr_driver_dump_find_next_free_entry(void)
62 {
63 	int i;
64 
65 	for (i = 0; i < CNSS_HOST_DUMP_TYPE_MAX; i++) {
66 		if (!dump_entry_list[i].buffer_pointer)
67 			return &dump_entry_list[i];
68 	}
69 	return NULL;
70 }
71 
72 static struct cnss_ssr_driver_dump_entry *
qdf_ssr_driver_dump_find_entry_by_name(char * region_name)73 qdf_ssr_driver_dump_find_entry_by_name(char *region_name)
74 {
75 	int i;
76 
77 	for (i = 0; i < CNSS_HOST_DUMP_TYPE_MAX; i++) {
78 		if (qdf_str_eq(dump_entry_list[i].region_name, region_name) &&
79 		    dump_entry_list[i].buffer_pointer) {
80 			return &dump_entry_list[i];
81 		}
82 	}
83 
84 	return NULL;
85 }
86 
87 QDF_STATUS
qdf_ssr_driver_dump_register_region(char * region_name,void * region_buffer,size_t region_size)88 qdf_ssr_driver_dump_register_region(char *region_name, void *region_buffer,
89 				    size_t region_size)
90 {
91 	QDF_STATUS status;
92 	struct cnss_ssr_driver_dump_entry *entry;
93 
94 	if (!region_buffer || !region_name) {
95 		qdf_err("null region pointer or region_name");
96 		return QDF_STATUS_E_NULL_VALUE;
97 	}
98 
99 	status = qdf_mutex_acquire(&region_list_mutex);
100 	if (QDF_IS_STATUS_ERROR(status)) {
101 		qdf_err("couldn't acquire lock");
102 		return QDF_STATUS_E_RESOURCES;
103 	}
104 
105 	entry = qdf_ssr_driver_dump_find_entry_by_name(region_name);
106 	if (entry) {
107 		qdf_err("duplicate registration of %s", region_name);
108 		status = QDF_STATUS_E_INVAL;
109 		goto ret;
110 	}
111 
112 	entry = qdf_ssr_driver_dump_find_next_free_entry();
113 	if (!entry) {
114 		qdf_err("too many entries: %d, cannot insert %s",
115 			num_of_regions_registered, region_name);
116 		status = QDF_STATUS_E_NOMEM;
117 		goto ret;
118 	}
119 
120 	entry->buffer_pointer = region_buffer;
121 	entry->buffer_size = region_size;
122 	qdf_str_lcopy(entry->region_name, region_name,
123 		      sizeof(entry->region_name));
124 	num_of_regions_registered++;
125 	goto ret;
126 
127 ret:
128 	if (QDF_IS_STATUS_ERROR(qdf_mutex_release(&region_list_mutex))) {
129 		qdf_err("error releasing lock");
130 		return QDF_STATUS_E_RESOURCES;
131 	}
132 	return status;
133 }
134 
qdf_ssr_driver_dump_unregister_region(char * region_name)135 QDF_STATUS qdf_ssr_driver_dump_unregister_region(char *region_name)
136 {
137 	QDF_STATUS status;
138 	struct cnss_ssr_driver_dump_entry *entry;
139 
140 	if (!region_name) {
141 		qdf_err("null region_name");
142 		return QDF_STATUS_E_NULL_VALUE;
143 	}
144 
145 	status = qdf_mutex_acquire(&region_list_mutex);
146 	if (QDF_IS_STATUS_ERROR(status)) {
147 		qdf_err("couldn't acquire lock");
148 		return QDF_STATUS_E_RESOURCES;
149 	}
150 
151 	entry = qdf_ssr_driver_dump_find_entry_by_name(region_name);
152 	if (!entry) {
153 		qdf_err("couldn't find entry: %s", region_name);
154 		status = QDF_STATUS_E_INVAL;
155 		goto ret;
156 	}
157 
158 	entry->buffer_pointer = NULL;
159 	num_of_regions_registered--;
160 
161 ret:
162 	if (QDF_IS_STATUS_ERROR(qdf_mutex_release(&region_list_mutex))) {
163 		qdf_err("error releasing lock");
164 		return QDF_STATUS_E_RESOURCES;
165 	}
166 	return status;
167 }
168 
169 QDF_STATUS
qdf_ssr_driver_dump_retrieve_regions(qdf_ssr_driver_dump_entry * input_array,size_t * num_entries_loaded)170 qdf_ssr_driver_dump_retrieve_regions(qdf_ssr_driver_dump_entry
171 				     *input_array,
172 				     size_t *num_entries_loaded)
173 {
174 	QDF_STATUS status;
175 	int i;
176 	size_t input_index = 0;
177 
178 	if (!input_array || !num_entries_loaded) {
179 		qdf_err("null input_array or num_entries_loaded");
180 		return QDF_STATUS_E_NULL_VALUE;
181 	}
182 
183 	status = qdf_mutex_acquire(&region_list_mutex);
184 	if (QDF_IS_STATUS_ERROR(status)) {
185 		qdf_err("couldn't acquire lock");
186 		return QDF_STATUS_E_RESOURCES;
187 	}
188 
189 	for (i = 0; i < CNSS_HOST_DUMP_TYPE_MAX; i++) {
190 		if (dump_entry_list[i].buffer_pointer) {
191 			qdf_mem_copy(&input_array[input_index],
192 				     &dump_entry_list[i],
193 				     sizeof(dump_entry_list[i]));
194 			input_index++;
195 		}
196 	}
197 	if (input_index != num_of_regions_registered) {
198 		qdf_err("num entries mismatch index:%d num reg registered:%d",
199 			input_index, num_of_regions_registered);
200 		status = QDF_STATUS_E_INVAL;
201 		goto ret;
202 	}
203 	*num_entries_loaded = input_index;
204 
205 ret:
206 	if (QDF_IS_STATUS_ERROR(qdf_mutex_release(&region_list_mutex))) {
207 		qdf_err("error releasing lock");
208 		return QDF_STATUS_E_RESOURCES;
209 	}
210 	return status;
211 }
212