/* * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "qdf_ssr_driver_dump.h" #include "qdf_lock.h" #include "qdf_str.h" #include #include #include #include #include #include static qdf_mutex_t region_list_mutex; static struct cnss_ssr_driver_dump_entry dump_entry_list[CNSS_HOST_DUMP_TYPE_MAX]; static size_t num_of_regions_registered; QDF_STATUS qdf_ssr_driver_dump_init(void) { QDF_STATUS status; status = qdf_mutex_create(®ion_list_mutex); if (QDF_IS_STATUS_ERROR(status)) return status; num_of_regions_registered = 0; qdf_mem_zero(dump_entry_list, sizeof(dump_entry_list)); return status; } QDF_STATUS qdf_ssr_driver_dump_deinit(void) { QDF_STATUS status; status = qdf_mutex_destroy(®ion_list_mutex); if (QDF_IS_STATUS_ERROR(status)) return status; if (num_of_regions_registered > 0) qdf_warn("deiniting with regions still registered"); num_of_regions_registered = 0; return status; } static struct cnss_ssr_driver_dump_entry * qdf_ssr_driver_dump_find_next_free_entry(void) { int i; for (i = 0; i < CNSS_HOST_DUMP_TYPE_MAX; i++) { if (!dump_entry_list[i].buffer_pointer) return &dump_entry_list[i]; } return NULL; } static struct cnss_ssr_driver_dump_entry * qdf_ssr_driver_dump_find_entry_by_name(char *region_name) { int i; for (i = 0; i < CNSS_HOST_DUMP_TYPE_MAX; i++) { if (qdf_str_eq(dump_entry_list[i].region_name, region_name) && dump_entry_list[i].buffer_pointer) { return &dump_entry_list[i]; } } return NULL; } QDF_STATUS qdf_ssr_driver_dump_register_region(char *region_name, void *region_buffer, size_t region_size) { QDF_STATUS status; struct cnss_ssr_driver_dump_entry *entry; if (!region_buffer || !region_name) { qdf_err("null region pointer or region_name"); return QDF_STATUS_E_NULL_VALUE; } status = qdf_mutex_acquire(®ion_list_mutex); if (QDF_IS_STATUS_ERROR(status)) { qdf_err("couldn't acquire lock"); return QDF_STATUS_E_RESOURCES; } entry = qdf_ssr_driver_dump_find_entry_by_name(region_name); if (entry) { qdf_err("duplicate registration of %s", region_name); status = QDF_STATUS_E_INVAL; goto ret; } entry = qdf_ssr_driver_dump_find_next_free_entry(); if (!entry) { qdf_err("too many entries: %d, cannot insert %s", num_of_regions_registered, region_name); status = QDF_STATUS_E_NOMEM; goto ret; } entry->buffer_pointer = region_buffer; entry->buffer_size = region_size; qdf_str_lcopy(entry->region_name, region_name, sizeof(entry->region_name)); num_of_regions_registered++; goto ret; ret: if (QDF_IS_STATUS_ERROR(qdf_mutex_release(®ion_list_mutex))) { qdf_err("error releasing lock"); return QDF_STATUS_E_RESOURCES; } return status; } QDF_STATUS qdf_ssr_driver_dump_unregister_region(char *region_name) { QDF_STATUS status; struct cnss_ssr_driver_dump_entry *entry; if (!region_name) { qdf_err("null region_name"); return QDF_STATUS_E_NULL_VALUE; } status = qdf_mutex_acquire(®ion_list_mutex); if (QDF_IS_STATUS_ERROR(status)) { qdf_err("couldn't acquire lock"); return QDF_STATUS_E_RESOURCES; } entry = qdf_ssr_driver_dump_find_entry_by_name(region_name); if (!entry) { qdf_err("couldn't find entry: %s", region_name); status = QDF_STATUS_E_INVAL; goto ret; } entry->buffer_pointer = NULL; num_of_regions_registered--; ret: if (QDF_IS_STATUS_ERROR(qdf_mutex_release(®ion_list_mutex))) { qdf_err("error releasing lock"); return QDF_STATUS_E_RESOURCES; } return status; } QDF_STATUS qdf_ssr_driver_dump_retrieve_regions(qdf_ssr_driver_dump_entry *input_array, size_t *num_entries_loaded) { QDF_STATUS status; int i; size_t input_index = 0; if (!input_array || !num_entries_loaded) { qdf_err("null input_array or num_entries_loaded"); return QDF_STATUS_E_NULL_VALUE; } status = qdf_mutex_acquire(®ion_list_mutex); if (QDF_IS_STATUS_ERROR(status)) { qdf_err("couldn't acquire lock"); return QDF_STATUS_E_RESOURCES; } for (i = 0; i < CNSS_HOST_DUMP_TYPE_MAX; i++) { if (dump_entry_list[i].buffer_pointer) { qdf_mem_copy(&input_array[input_index], &dump_entry_list[i], sizeof(dump_entry_list[i])); input_index++; } } if (input_index != num_of_regions_registered) { qdf_err("num entries mismatch index:%d num reg registered:%d", input_index, num_of_regions_registered); status = QDF_STATUS_E_INVAL; goto ret; } *num_entries_loaded = input_index; ret: if (QDF_IS_STATUS_ERROR(qdf_mutex_release(®ion_list_mutex))) { qdf_err("error releasing lock"); return QDF_STATUS_E_RESOURCES; } return status; }