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 34 QDF_STATUS qdf_ssr_driver_dump_init(void) 35 { 36 QDF_STATUS status; 37 38 status = qdf_mutex_create(®ion_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 47 QDF_STATUS qdf_ssr_driver_dump_deinit(void) 48 { 49 QDF_STATUS status; 50 51 status = qdf_mutex_destroy(®ion_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 * 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 * 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 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(®ion_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(®ion_list_mutex))) { 129 qdf_err("error releasing lock"); 130 return QDF_STATUS_E_RESOURCES; 131 } 132 return status; 133 } 134 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(®ion_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(®ion_list_mutex))) { 163 qdf_err("error releasing lock"); 164 return QDF_STATUS_E_RESOURCES; 165 } 166 return status; 167 } 168 169 QDF_STATUS 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(®ion_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(®ion_list_mutex))) { 207 qdf_err("error releasing lock"); 208 return QDF_STATUS_E_RESOURCES; 209 } 210 return status; 211 } 212