162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: uttrack - Memory allocation tracking routines (debug only) 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * These procedures are used for tracking memory leaks in the subsystem, and 1262306a36Sopenharmony_ci * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Each memory allocation is tracked via a doubly linked list. Each 1562306a36Sopenharmony_ci * element contains the caller's component, module name, function name, and 1662306a36Sopenharmony_ci * line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call 1762306a36Sopenharmony_ci * acpi_ut_track_allocation to add an element to the list; deletion 1862306a36Sopenharmony_ci * occurs in the body of acpi_ut_free. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <acpi/acpi.h> 2262306a36Sopenharmony_ci#include "accommon.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#ifdef ACPI_DBG_TRACK_ALLOCATIONS 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define _COMPONENT ACPI_UTILITIES 2762306a36Sopenharmony_ciACPI_MODULE_NAME("uttrack") 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* Local prototypes */ 3062306a36Sopenharmony_cistatic struct acpi_debug_mem_block *acpi_ut_find_allocation(struct 3162306a36Sopenharmony_ci acpi_debug_mem_block 3262306a36Sopenharmony_ci *allocation); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic acpi_status 3562306a36Sopenharmony_ciacpi_ut_track_allocation(struct acpi_debug_mem_block *address, 3662306a36Sopenharmony_ci acpi_size size, 3762306a36Sopenharmony_ci u8 alloc_type, 3862306a36Sopenharmony_ci u32 component, const char *module, u32 line); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic acpi_status 4162306a36Sopenharmony_ciacpi_ut_remove_allocation(struct acpi_debug_mem_block *address, 4262306a36Sopenharmony_ci u32 component, const char *module, u32 line); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/******************************************************************************* 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * FUNCTION: acpi_ut_create_list 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * PARAMETERS: cache_name - Ascii name for the cache 4962306a36Sopenharmony_ci * object_size - Size of each cached object 5062306a36Sopenharmony_ci * return_cache - Where the new cache object is returned 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * RETURN: Status 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * DESCRIPTION: Create a local memory list for tracking purposed 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci ******************************************************************************/ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciacpi_status 5962306a36Sopenharmony_ciacpi_ut_create_list(const char *list_name, 6062306a36Sopenharmony_ci u16 object_size, struct acpi_memory_list **return_cache) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct acpi_memory_list *cache; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci cache = acpi_os_allocate_zeroed(sizeof(struct acpi_memory_list)); 6562306a36Sopenharmony_ci if (!cache) { 6662306a36Sopenharmony_ci return (AE_NO_MEMORY); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci cache->list_name = list_name; 7062306a36Sopenharmony_ci cache->object_size = object_size; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci *return_cache = cache; 7362306a36Sopenharmony_ci return (AE_OK); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/******************************************************************************* 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * FUNCTION: acpi_ut_allocate_and_track 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * PARAMETERS: size - Size of the allocation 8162306a36Sopenharmony_ci * component - Component type of caller 8262306a36Sopenharmony_ci * module - Source file name of caller 8362306a36Sopenharmony_ci * line - Line number of caller 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * RETURN: Address of the allocated memory on success, NULL on failure. 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * DESCRIPTION: The subsystem's equivalent of malloc. 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci ******************************************************************************/ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_civoid *acpi_ut_allocate_and_track(acpi_size size, 9262306a36Sopenharmony_ci u32 component, const char *module, u32 line) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct acpi_debug_mem_block *allocation; 9562306a36Sopenharmony_ci acpi_status status; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Check for an inadvertent size of zero bytes */ 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (!size) { 10062306a36Sopenharmony_ci ACPI_WARNING((module, line, 10162306a36Sopenharmony_ci "Attempt to allocate zero bytes, allocating 1 byte")); 10262306a36Sopenharmony_ci size = 1; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci allocation = 10662306a36Sopenharmony_ci acpi_os_allocate(size + sizeof(struct acpi_debug_mem_header)); 10762306a36Sopenharmony_ci if (!allocation) { 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Report allocation error */ 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ACPI_WARNING((module, line, 11262306a36Sopenharmony_ci "Could not allocate size %u", (u32)size)); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return (NULL); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci status = 11862306a36Sopenharmony_ci acpi_ut_track_allocation(allocation, size, ACPI_MEM_MALLOC, 11962306a36Sopenharmony_ci component, module, line); 12062306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 12162306a36Sopenharmony_ci acpi_os_free(allocation); 12262306a36Sopenharmony_ci return (NULL); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci acpi_gbl_global_list->total_allocated++; 12662306a36Sopenharmony_ci acpi_gbl_global_list->total_size += (u32)size; 12762306a36Sopenharmony_ci acpi_gbl_global_list->current_total_size += (u32)size; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (acpi_gbl_global_list->current_total_size > 13062306a36Sopenharmony_ci acpi_gbl_global_list->max_occupied) { 13162306a36Sopenharmony_ci acpi_gbl_global_list->max_occupied = 13262306a36Sopenharmony_ci acpi_gbl_global_list->current_total_size; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return ((void *)&allocation->user_space); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/******************************************************************************* 13962306a36Sopenharmony_ci * 14062306a36Sopenharmony_ci * FUNCTION: acpi_ut_allocate_zeroed_and_track 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * PARAMETERS: size - Size of the allocation 14362306a36Sopenharmony_ci * component - Component type of caller 14462306a36Sopenharmony_ci * module - Source file name of caller 14562306a36Sopenharmony_ci * line - Line number of caller 14662306a36Sopenharmony_ci * 14762306a36Sopenharmony_ci * RETURN: Address of the allocated memory on success, NULL on failure. 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * DESCRIPTION: Subsystem equivalent of calloc. 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci ******************************************************************************/ 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_civoid *acpi_ut_allocate_zeroed_and_track(acpi_size size, 15462306a36Sopenharmony_ci u32 component, 15562306a36Sopenharmony_ci const char *module, u32 line) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct acpi_debug_mem_block *allocation; 15862306a36Sopenharmony_ci acpi_status status; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Check for an inadvertent size of zero bytes */ 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (!size) { 16362306a36Sopenharmony_ci ACPI_WARNING((module, line, 16462306a36Sopenharmony_ci "Attempt to allocate zero bytes, allocating 1 byte")); 16562306a36Sopenharmony_ci size = 1; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci allocation = 16962306a36Sopenharmony_ci acpi_os_allocate_zeroed(size + 17062306a36Sopenharmony_ci sizeof(struct acpi_debug_mem_header)); 17162306a36Sopenharmony_ci if (!allocation) { 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Report allocation error */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci ACPI_ERROR((module, line, 17662306a36Sopenharmony_ci "Could not allocate size %u", (u32)size)); 17762306a36Sopenharmony_ci return (NULL); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci status = acpi_ut_track_allocation(allocation, size, 18162306a36Sopenharmony_ci ACPI_MEM_CALLOC, component, module, 18262306a36Sopenharmony_ci line); 18362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 18462306a36Sopenharmony_ci acpi_os_free(allocation); 18562306a36Sopenharmony_ci return (NULL); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci acpi_gbl_global_list->total_allocated++; 18962306a36Sopenharmony_ci acpi_gbl_global_list->total_size += (u32)size; 19062306a36Sopenharmony_ci acpi_gbl_global_list->current_total_size += (u32)size; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (acpi_gbl_global_list->current_total_size > 19362306a36Sopenharmony_ci acpi_gbl_global_list->max_occupied) { 19462306a36Sopenharmony_ci acpi_gbl_global_list->max_occupied = 19562306a36Sopenharmony_ci acpi_gbl_global_list->current_total_size; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return ((void *)&allocation->user_space); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/******************************************************************************* 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * FUNCTION: acpi_ut_free_and_track 20462306a36Sopenharmony_ci * 20562306a36Sopenharmony_ci * PARAMETERS: allocation - Address of the memory to deallocate 20662306a36Sopenharmony_ci * component - Component type of caller 20762306a36Sopenharmony_ci * module - Source file name of caller 20862306a36Sopenharmony_ci * line - Line number of caller 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * RETURN: None 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * DESCRIPTION: Frees the memory at Allocation 21362306a36Sopenharmony_ci * 21462306a36Sopenharmony_ci ******************************************************************************/ 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_civoid 21762306a36Sopenharmony_ciacpi_ut_free_and_track(void *allocation, 21862306a36Sopenharmony_ci u32 component, const char *module, u32 line) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct acpi_debug_mem_block *debug_block; 22162306a36Sopenharmony_ci acpi_status status; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ut_free, allocation); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (NULL == allocation) { 22662306a36Sopenharmony_ci ACPI_ERROR((module, line, "Attempt to delete a NULL address")); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return_VOID; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci debug_block = ACPI_CAST_PTR(struct acpi_debug_mem_block, 23262306a36Sopenharmony_ci (((char *)allocation) - 23362306a36Sopenharmony_ci sizeof(struct acpi_debug_mem_header))); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci acpi_gbl_global_list->total_freed++; 23662306a36Sopenharmony_ci acpi_gbl_global_list->current_total_size -= debug_block->size; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci status = 23962306a36Sopenharmony_ci acpi_ut_remove_allocation(debug_block, component, module, line); 24062306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 24162306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, "Could not free memory")); 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci acpi_os_free(debug_block); 24562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n", 24662306a36Sopenharmony_ci allocation, debug_block)); 24762306a36Sopenharmony_ci return_VOID; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/******************************************************************************* 25162306a36Sopenharmony_ci * 25262306a36Sopenharmony_ci * FUNCTION: acpi_ut_find_allocation 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * PARAMETERS: allocation - Address of allocated memory 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * RETURN: Three cases: 25762306a36Sopenharmony_ci * 1) List is empty, NULL is returned. 25862306a36Sopenharmony_ci * 2) Element was found. Returns Allocation parameter. 25962306a36Sopenharmony_ci * 3) Element was not found. Returns position where it should be 26062306a36Sopenharmony_ci * inserted into the list. 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * DESCRIPTION: Searches for an element in the global allocation tracking list. 26362306a36Sopenharmony_ci * If the element is not found, returns the location within the 26462306a36Sopenharmony_ci * list where the element should be inserted. 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * Note: The list is ordered by larger-to-smaller addresses. 26762306a36Sopenharmony_ci * 26862306a36Sopenharmony_ci * This global list is used to detect memory leaks in ACPICA as 26962306a36Sopenharmony_ci * well as other issues such as an attempt to release the same 27062306a36Sopenharmony_ci * internal object more than once. Although expensive as far 27162306a36Sopenharmony_ci * as cpu time, this list is much more helpful for finding these 27262306a36Sopenharmony_ci * types of issues than using memory leak detectors outside of 27362306a36Sopenharmony_ci * the ACPICA code. 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci ******************************************************************************/ 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic struct acpi_debug_mem_block *acpi_ut_find_allocation(struct 27862306a36Sopenharmony_ci acpi_debug_mem_block 27962306a36Sopenharmony_ci *allocation) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct acpi_debug_mem_block *element; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci element = acpi_gbl_global_list->list_head; 28462306a36Sopenharmony_ci if (!element) { 28562306a36Sopenharmony_ci return (NULL); 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* 28962306a36Sopenharmony_ci * Search for the address. 29062306a36Sopenharmony_ci * 29162306a36Sopenharmony_ci * Note: List is ordered by larger-to-smaller addresses, on the 29262306a36Sopenharmony_ci * assumption that a new allocation usually has a larger address 29362306a36Sopenharmony_ci * than previous allocations. 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_ci while (element > allocation) { 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* Check for end-of-list */ 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (!element->next) { 30062306a36Sopenharmony_ci return (element); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci element = element->next; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (element == allocation) { 30762306a36Sopenharmony_ci return (element); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci return (element->previous); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/******************************************************************************* 31462306a36Sopenharmony_ci * 31562306a36Sopenharmony_ci * FUNCTION: acpi_ut_track_allocation 31662306a36Sopenharmony_ci * 31762306a36Sopenharmony_ci * PARAMETERS: allocation - Address of allocated memory 31862306a36Sopenharmony_ci * size - Size of the allocation 31962306a36Sopenharmony_ci * alloc_type - MEM_MALLOC or MEM_CALLOC 32062306a36Sopenharmony_ci * component - Component type of caller 32162306a36Sopenharmony_ci * module - Source file name of caller 32262306a36Sopenharmony_ci * line - Line number of caller 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci * RETURN: Status 32562306a36Sopenharmony_ci * 32662306a36Sopenharmony_ci * DESCRIPTION: Inserts an element into the global allocation tracking list. 32762306a36Sopenharmony_ci * 32862306a36Sopenharmony_ci ******************************************************************************/ 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic acpi_status 33162306a36Sopenharmony_ciacpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, 33262306a36Sopenharmony_ci acpi_size size, 33362306a36Sopenharmony_ci u8 alloc_type, 33462306a36Sopenharmony_ci u32 component, const char *module, u32 line) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct acpi_memory_list *mem_list; 33762306a36Sopenharmony_ci struct acpi_debug_mem_block *element; 33862306a36Sopenharmony_ci acpi_status status = AE_OK; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ut_track_allocation, allocation); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (acpi_gbl_disable_mem_tracking) { 34362306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci mem_list = acpi_gbl_global_list; 34762306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY); 34862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 34962306a36Sopenharmony_ci return_ACPI_STATUS(status); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* 35362306a36Sopenharmony_ci * Search the global list for this address to make sure it is not 35462306a36Sopenharmony_ci * already present. This will catch several kinds of problems. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ci element = acpi_ut_find_allocation(allocation); 35762306a36Sopenharmony_ci if (element == allocation) { 35862306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 35962306a36Sopenharmony_ci "UtTrackAllocation: Allocation (%p) already present in global list!", 36062306a36Sopenharmony_ci allocation)); 36162306a36Sopenharmony_ci goto unlock_and_exit; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* Fill in the instance data */ 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci allocation->size = (u32)size; 36762306a36Sopenharmony_ci allocation->alloc_type = alloc_type; 36862306a36Sopenharmony_ci allocation->component = component; 36962306a36Sopenharmony_ci allocation->line = line; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci acpi_ut_safe_strncpy(allocation->module, (char *)module, 37262306a36Sopenharmony_ci ACPI_MAX_MODULE_NAME); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (!element) { 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Insert at list head */ 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (mem_list->list_head) { 37962306a36Sopenharmony_ci ((struct acpi_debug_mem_block *)(mem_list->list_head))-> 38062306a36Sopenharmony_ci previous = allocation; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci allocation->next = mem_list->list_head; 38462306a36Sopenharmony_ci allocation->previous = NULL; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci mem_list->list_head = allocation; 38762306a36Sopenharmony_ci } else { 38862306a36Sopenharmony_ci /* Insert after element */ 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci allocation->next = element->next; 39162306a36Sopenharmony_ci allocation->previous = element; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (element->next) { 39462306a36Sopenharmony_ci (element->next)->previous = allocation; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci element->next = allocation; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ciunlock_and_exit: 40162306a36Sopenharmony_ci status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); 40262306a36Sopenharmony_ci return_ACPI_STATUS(status); 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/******************************************************************************* 40662306a36Sopenharmony_ci * 40762306a36Sopenharmony_ci * FUNCTION: acpi_ut_remove_allocation 40862306a36Sopenharmony_ci * 40962306a36Sopenharmony_ci * PARAMETERS: allocation - Address of allocated memory 41062306a36Sopenharmony_ci * component - Component type of caller 41162306a36Sopenharmony_ci * module - Source file name of caller 41262306a36Sopenharmony_ci * line - Line number of caller 41362306a36Sopenharmony_ci * 41462306a36Sopenharmony_ci * RETURN: Status 41562306a36Sopenharmony_ci * 41662306a36Sopenharmony_ci * DESCRIPTION: Deletes an element from the global allocation tracking list. 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci ******************************************************************************/ 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic acpi_status 42162306a36Sopenharmony_ciacpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation, 42262306a36Sopenharmony_ci u32 component, const char *module, u32 line) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct acpi_memory_list *mem_list; 42562306a36Sopenharmony_ci acpi_status status; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci ACPI_FUNCTION_NAME(ut_remove_allocation); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (acpi_gbl_disable_mem_tracking) { 43062306a36Sopenharmony_ci return (AE_OK); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci mem_list = acpi_gbl_global_list; 43462306a36Sopenharmony_ci if (NULL == mem_list->list_head) { 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* No allocations! */ 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci ACPI_ERROR((module, line, 43962306a36Sopenharmony_ci "Empty allocation list, nothing to free!")); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return (AE_OK); 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY); 44562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 44662306a36Sopenharmony_ci return (status); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* Unlink */ 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (allocation->previous) { 45262306a36Sopenharmony_ci (allocation->previous)->next = allocation->next; 45362306a36Sopenharmony_ci } else { 45462306a36Sopenharmony_ci mem_list->list_head = allocation->next; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (allocation->next) { 45862306a36Sopenharmony_ci (allocation->next)->previous = allocation->previous; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n", 46262306a36Sopenharmony_ci &allocation->user_space, allocation->size)); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* Mark the segment as deleted */ 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci memset(&allocation->user_space, 0xEA, allocation->size); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); 46962306a36Sopenharmony_ci return (status); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci/******************************************************************************* 47362306a36Sopenharmony_ci * 47462306a36Sopenharmony_ci * FUNCTION: acpi_ut_dump_allocation_info 47562306a36Sopenharmony_ci * 47662306a36Sopenharmony_ci * PARAMETERS: None 47762306a36Sopenharmony_ci * 47862306a36Sopenharmony_ci * RETURN: None 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci * DESCRIPTION: Print some info about the outstanding allocations. 48162306a36Sopenharmony_ci * 48262306a36Sopenharmony_ci ******************************************************************************/ 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_civoid acpi_ut_dump_allocation_info(void) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci/* 48762306a36Sopenharmony_ci struct acpi_memory_list *mem_list; 48862306a36Sopenharmony_ci*/ 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ut_dump_allocation_info); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci/* 49362306a36Sopenharmony_ci ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 49462306a36Sopenharmony_ci ("%30s: %4d (%3d Kb)\n", "Current allocations", 49562306a36Sopenharmony_ci mem_list->current_count, 49662306a36Sopenharmony_ci ROUND_UP_TO_1K (mem_list->current_size))); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 49962306a36Sopenharmony_ci ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations", 50062306a36Sopenharmony_ci mem_list->max_concurrent_count, 50162306a36Sopenharmony_ci ROUND_UP_TO_1K (mem_list->max_concurrent_size))); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 50462306a36Sopenharmony_ci ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects", 50562306a36Sopenharmony_ci running_object_count, 50662306a36Sopenharmony_ci ROUND_UP_TO_1K (running_object_size))); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 50962306a36Sopenharmony_ci ("%30s: %4d (%3d Kb)\n", "Total (all) allocations", 51062306a36Sopenharmony_ci running_alloc_count, 51162306a36Sopenharmony_ci ROUND_UP_TO_1K (running_alloc_size))); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 51462306a36Sopenharmony_ci ("%30s: %4d (%3d Kb)\n", "Current Nodes", 51562306a36Sopenharmony_ci acpi_gbl_current_node_count, 51662306a36Sopenharmony_ci ROUND_UP_TO_1K (acpi_gbl_current_node_size))); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 51962306a36Sopenharmony_ci ("%30s: %4d (%3d Kb)\n", "Max Nodes", 52062306a36Sopenharmony_ci acpi_gbl_max_concurrent_node_count, 52162306a36Sopenharmony_ci ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * 52262306a36Sopenharmony_ci sizeof (struct acpi_namespace_node))))); 52362306a36Sopenharmony_ci*/ 52462306a36Sopenharmony_ci return_VOID; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci/******************************************************************************* 52862306a36Sopenharmony_ci * 52962306a36Sopenharmony_ci * FUNCTION: acpi_ut_dump_allocations 53062306a36Sopenharmony_ci * 53162306a36Sopenharmony_ci * PARAMETERS: component - Component(s) to dump info for. 53262306a36Sopenharmony_ci * module - Module to dump info for. NULL means all. 53362306a36Sopenharmony_ci * 53462306a36Sopenharmony_ci * RETURN: None 53562306a36Sopenharmony_ci * 53662306a36Sopenharmony_ci * DESCRIPTION: Print a list of all outstanding allocations. 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci ******************************************************************************/ 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_civoid acpi_ut_dump_allocations(u32 component, const char *module) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct acpi_debug_mem_block *element; 54362306a36Sopenharmony_ci union acpi_descriptor *descriptor; 54462306a36Sopenharmony_ci u32 num_outstanding = 0; 54562306a36Sopenharmony_ci u8 descriptor_type; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ut_dump_allocations); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (acpi_gbl_disable_mem_tracking) { 55062306a36Sopenharmony_ci return_VOID; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* 55462306a36Sopenharmony_ci * Walk the allocation list. 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_ci if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) { 55762306a36Sopenharmony_ci return_VOID; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (!acpi_gbl_global_list) { 56162306a36Sopenharmony_ci goto exit; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci element = acpi_gbl_global_list->list_head; 56562306a36Sopenharmony_ci while (element) { 56662306a36Sopenharmony_ci if ((element->component & component) && 56762306a36Sopenharmony_ci ((module == NULL) 56862306a36Sopenharmony_ci || (0 == strcmp(module, element->module)))) { 56962306a36Sopenharmony_ci descriptor = 57062306a36Sopenharmony_ci ACPI_CAST_PTR(union acpi_descriptor, 57162306a36Sopenharmony_ci &element->user_space); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (element->size < 57462306a36Sopenharmony_ci sizeof(struct acpi_common_descriptor)) { 57562306a36Sopenharmony_ci acpi_os_printf("%p Length 0x%04X %9.9s-%4.4u " 57662306a36Sopenharmony_ci "[Not a Descriptor - too small]\n", 57762306a36Sopenharmony_ci descriptor, element->size, 57862306a36Sopenharmony_ci element->module, element->line); 57962306a36Sopenharmony_ci } else { 58062306a36Sopenharmony_ci /* Ignore allocated objects that are in a cache */ 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (ACPI_GET_DESCRIPTOR_TYPE(descriptor) != 58362306a36Sopenharmony_ci ACPI_DESC_TYPE_CACHED) { 58462306a36Sopenharmony_ci acpi_os_printf 58562306a36Sopenharmony_ci ("%p Length 0x%04X %9.9s-%4.4u [%s] ", 58662306a36Sopenharmony_ci descriptor, element->size, 58762306a36Sopenharmony_ci element->module, element->line, 58862306a36Sopenharmony_ci acpi_ut_get_descriptor_name 58962306a36Sopenharmony_ci (descriptor)); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* Optional object hex dump */ 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (acpi_gbl_verbose_leak_dump) { 59462306a36Sopenharmony_ci acpi_os_printf("\n"); 59562306a36Sopenharmony_ci acpi_ut_dump_buffer((u8 *) 59662306a36Sopenharmony_ci descriptor, 59762306a36Sopenharmony_ci element-> 59862306a36Sopenharmony_ci size, 59962306a36Sopenharmony_ci DB_BYTE_DISPLAY, 60062306a36Sopenharmony_ci 0); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* Validate the descriptor type using Type field and length */ 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci descriptor_type = 0; /* Not a valid descriptor type */ 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci switch (ACPI_GET_DESCRIPTOR_TYPE 60862306a36Sopenharmony_ci (descriptor)) { 60962306a36Sopenharmony_ci case ACPI_DESC_TYPE_OPERAND: 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (element->size == 61262306a36Sopenharmony_ci sizeof(union 61362306a36Sopenharmony_ci acpi_operand_object)) 61462306a36Sopenharmony_ci { 61562306a36Sopenharmony_ci descriptor_type = 61662306a36Sopenharmony_ci ACPI_DESC_TYPE_OPERAND; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci case ACPI_DESC_TYPE_PARSER: 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (element->size == 62362306a36Sopenharmony_ci sizeof(union 62462306a36Sopenharmony_ci acpi_parse_object)) { 62562306a36Sopenharmony_ci descriptor_type = 62662306a36Sopenharmony_ci ACPI_DESC_TYPE_PARSER; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci case ACPI_DESC_TYPE_NAMED: 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (element->size == 63362306a36Sopenharmony_ci sizeof(struct 63462306a36Sopenharmony_ci acpi_namespace_node)) 63562306a36Sopenharmony_ci { 63662306a36Sopenharmony_ci descriptor_type = 63762306a36Sopenharmony_ci ACPI_DESC_TYPE_NAMED; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci default: 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Display additional info for the major descriptor types */ 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci switch (descriptor_type) { 64962306a36Sopenharmony_ci case ACPI_DESC_TYPE_OPERAND: 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci acpi_os_printf 65262306a36Sopenharmony_ci ("%12.12s RefCount 0x%04X\n", 65362306a36Sopenharmony_ci acpi_ut_get_type_name 65462306a36Sopenharmony_ci (descriptor->object.common. 65562306a36Sopenharmony_ci type), 65662306a36Sopenharmony_ci descriptor->object.common. 65762306a36Sopenharmony_ci reference_count); 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci case ACPI_DESC_TYPE_PARSER: 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci acpi_os_printf 66362306a36Sopenharmony_ci ("AmlOpcode 0x%04X\n", 66462306a36Sopenharmony_ci descriptor->op.asl. 66562306a36Sopenharmony_ci aml_opcode); 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci case ACPI_DESC_TYPE_NAMED: 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci acpi_os_printf("%4.4s\n", 67162306a36Sopenharmony_ci acpi_ut_get_node_name 67262306a36Sopenharmony_ci (&descriptor-> 67362306a36Sopenharmony_ci node)); 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci default: 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci acpi_os_printf("\n"); 67962306a36Sopenharmony_ci break; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci num_outstanding++; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci element = element->next; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ciexit: 69162306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_MEMORY); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* Print summary */ 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (!num_outstanding) { 69662306a36Sopenharmony_ci ACPI_INFO(("No outstanding allocations")); 69762306a36Sopenharmony_ci } else { 69862306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "%u (0x%X) Outstanding cache allocations", 69962306a36Sopenharmony_ci num_outstanding, num_outstanding)); 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci return_VOID; 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ 706