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