xref: /openbmc/linux/drivers/acpi/acpica/utcache.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
26d33b6beSLv Zheng /******************************************************************************
36d33b6beSLv Zheng  *
46d33b6beSLv Zheng  * Module Name: utcache - local cache allocation routines
56d33b6beSLv Zheng  *
6*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
76d33b6beSLv Zheng  *
895857638SErik Schmauss  *****************************************************************************/
96d33b6beSLv Zheng 
106d33b6beSLv Zheng #include <acpi/acpi.h>
116d33b6beSLv Zheng #include "accommon.h"
126d33b6beSLv Zheng 
136d33b6beSLv Zheng #define _COMPONENT          ACPI_UTILITIES
146d33b6beSLv Zheng ACPI_MODULE_NAME("utcache")
156d33b6beSLv Zheng 
166d33b6beSLv Zheng #ifdef ACPI_USE_LOCAL_CACHE
176d33b6beSLv Zheng /*******************************************************************************
186d33b6beSLv Zheng  *
196d33b6beSLv Zheng  * FUNCTION:    acpi_os_create_cache
206d33b6beSLv Zheng  *
216d33b6beSLv Zheng  * PARAMETERS:  cache_name      - Ascii name for the cache
226d33b6beSLv Zheng  *              object_size     - Size of each cached object
236d33b6beSLv Zheng  *              max_depth       - Maximum depth of the cache (in objects)
246d33b6beSLv Zheng  *              return_cache    - Where the new cache object is returned
256d33b6beSLv Zheng  *
266d33b6beSLv Zheng  * RETURN:      Status
276d33b6beSLv Zheng  *
286d33b6beSLv Zheng  * DESCRIPTION: Create a cache object
296d33b6beSLv Zheng  *
306d33b6beSLv Zheng  ******************************************************************************/
316d33b6beSLv Zheng acpi_status
acpi_os_create_cache(char * cache_name,u16 object_size,u16 max_depth,struct acpi_memory_list ** return_cache)326d33b6beSLv Zheng acpi_os_create_cache(char *cache_name,
336d33b6beSLv Zheng 		     u16 object_size,
346d33b6beSLv Zheng 		     u16 max_depth, struct acpi_memory_list **return_cache)
356d33b6beSLv Zheng {
366d33b6beSLv Zheng 	struct acpi_memory_list *cache;
376d33b6beSLv Zheng 
386d33b6beSLv Zheng 	ACPI_FUNCTION_ENTRY();
396d33b6beSLv Zheng 
40c8e8ab1eSBob Moore 	if (!cache_name || !return_cache || !object_size) {
416d33b6beSLv Zheng 		return (AE_BAD_PARAMETER);
426d33b6beSLv Zheng 	}
436d33b6beSLv Zheng 
446d33b6beSLv Zheng 	/* Create the cache object */
456d33b6beSLv Zheng 
466d33b6beSLv Zheng 	cache = acpi_os_allocate(sizeof(struct acpi_memory_list));
476d33b6beSLv Zheng 	if (!cache) {
486d33b6beSLv Zheng 		return (AE_NO_MEMORY);
496d33b6beSLv Zheng 	}
506d33b6beSLv Zheng 
516d33b6beSLv Zheng 	/* Populate the cache object and return it */
526d33b6beSLv Zheng 
534fa4616eSBob Moore 	memset(cache, 0, sizeof(struct acpi_memory_list));
546d33b6beSLv Zheng 	cache->list_name = cache_name;
556d33b6beSLv Zheng 	cache->object_size = object_size;
566d33b6beSLv Zheng 	cache->max_depth = max_depth;
576d33b6beSLv Zheng 
586d33b6beSLv Zheng 	*return_cache = cache;
596d33b6beSLv Zheng 	return (AE_OK);
606d33b6beSLv Zheng }
616d33b6beSLv Zheng 
626d33b6beSLv Zheng /*******************************************************************************
636d33b6beSLv Zheng  *
646d33b6beSLv Zheng  * FUNCTION:    acpi_os_purge_cache
656d33b6beSLv Zheng  *
666d33b6beSLv Zheng  * PARAMETERS:  cache           - Handle to cache object
676d33b6beSLv Zheng  *
686d33b6beSLv Zheng  * RETURN:      Status
696d33b6beSLv Zheng  *
706d33b6beSLv Zheng  * DESCRIPTION: Free all objects within the requested cache.
716d33b6beSLv Zheng  *
726d33b6beSLv Zheng  ******************************************************************************/
736d33b6beSLv Zheng 
acpi_os_purge_cache(struct acpi_memory_list * cache)746d33b6beSLv Zheng acpi_status acpi_os_purge_cache(struct acpi_memory_list *cache)
756d33b6beSLv Zheng {
763cf24497SJung-uk Kim 	void *next;
776d33b6beSLv Zheng 	acpi_status status;
786d33b6beSLv Zheng 
796d33b6beSLv Zheng 	ACPI_FUNCTION_ENTRY();
806d33b6beSLv Zheng 
816d33b6beSLv Zheng 	if (!cache) {
826d33b6beSLv Zheng 		return (AE_BAD_PARAMETER);
836d33b6beSLv Zheng 	}
846d33b6beSLv Zheng 
856d33b6beSLv Zheng 	status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
866d33b6beSLv Zheng 	if (ACPI_FAILURE(status)) {
876d33b6beSLv Zheng 		return (status);
886d33b6beSLv Zheng 	}
896d33b6beSLv Zheng 
906d33b6beSLv Zheng 	/* Walk the list of objects in this cache */
916d33b6beSLv Zheng 
926d33b6beSLv Zheng 	while (cache->list_head) {
936d33b6beSLv Zheng 
946d33b6beSLv Zheng 		/* Delete and unlink one cached state object */
956d33b6beSLv Zheng 
961af89271SJung-uk Kim 		next = ACPI_GET_DESCRIPTOR_PTR(cache->list_head);
976d33b6beSLv Zheng 		ACPI_FREE(cache->list_head);
986d33b6beSLv Zheng 
996d33b6beSLv Zheng 		cache->list_head = next;
1006d33b6beSLv Zheng 		cache->current_depth--;
1016d33b6beSLv Zheng 	}
1026d33b6beSLv Zheng 
1036d33b6beSLv Zheng 	(void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
1046d33b6beSLv Zheng 	return (AE_OK);
1056d33b6beSLv Zheng }
1066d33b6beSLv Zheng 
1076d33b6beSLv Zheng /*******************************************************************************
1086d33b6beSLv Zheng  *
1096d33b6beSLv Zheng  * FUNCTION:    acpi_os_delete_cache
1106d33b6beSLv Zheng  *
1116d33b6beSLv Zheng  * PARAMETERS:  cache           - Handle to cache object
1126d33b6beSLv Zheng  *
1136d33b6beSLv Zheng  * RETURN:      Status
1146d33b6beSLv Zheng  *
1156d33b6beSLv Zheng  * DESCRIPTION: Free all objects within the requested cache and delete the
1166d33b6beSLv Zheng  *              cache object.
1176d33b6beSLv Zheng  *
1186d33b6beSLv Zheng  ******************************************************************************/
1196d33b6beSLv Zheng 
acpi_os_delete_cache(struct acpi_memory_list * cache)1206d33b6beSLv Zheng acpi_status acpi_os_delete_cache(struct acpi_memory_list *cache)
1216d33b6beSLv Zheng {
1226d33b6beSLv Zheng 	acpi_status status;
1236d33b6beSLv Zheng 
1246d33b6beSLv Zheng 	ACPI_FUNCTION_ENTRY();
1256d33b6beSLv Zheng 
1266d33b6beSLv Zheng 	/* Purge all objects in the cache */
1276d33b6beSLv Zheng 
1286d33b6beSLv Zheng 	status = acpi_os_purge_cache(cache);
1296d33b6beSLv Zheng 	if (ACPI_FAILURE(status)) {
1306d33b6beSLv Zheng 		return (status);
1316d33b6beSLv Zheng 	}
1326d33b6beSLv Zheng 
1336d33b6beSLv Zheng 	/* Now we can delete the cache object */
1346d33b6beSLv Zheng 
1356d33b6beSLv Zheng 	acpi_os_free(cache);
1366d33b6beSLv Zheng 	return (AE_OK);
1376d33b6beSLv Zheng }
1386d33b6beSLv Zheng 
1396d33b6beSLv Zheng /*******************************************************************************
1406d33b6beSLv Zheng  *
1416d33b6beSLv Zheng  * FUNCTION:    acpi_os_release_object
1426d33b6beSLv Zheng  *
1436d33b6beSLv Zheng  * PARAMETERS:  cache       - Handle to cache object
1446d33b6beSLv Zheng  *              object      - The object to be released
1456d33b6beSLv Zheng  *
1466d33b6beSLv Zheng  * RETURN:      None
1476d33b6beSLv Zheng  *
1486d33b6beSLv Zheng  * DESCRIPTION: Release an object to the specified cache. If cache is full,
1496d33b6beSLv Zheng  *              the object is deleted.
1506d33b6beSLv Zheng  *
1516d33b6beSLv Zheng  ******************************************************************************/
1526d33b6beSLv Zheng 
acpi_os_release_object(struct acpi_memory_list * cache,void * object)153f5c1e1c5SLv Zheng acpi_status acpi_os_release_object(struct acpi_memory_list *cache, void *object)
1546d33b6beSLv Zheng {
1556d33b6beSLv Zheng 	acpi_status status;
1566d33b6beSLv Zheng 
1576d33b6beSLv Zheng 	ACPI_FUNCTION_ENTRY();
1586d33b6beSLv Zheng 
1596d33b6beSLv Zheng 	if (!cache || !object) {
1606d33b6beSLv Zheng 		return (AE_BAD_PARAMETER);
1616d33b6beSLv Zheng 	}
1626d33b6beSLv Zheng 
1636d33b6beSLv Zheng 	/* If cache is full, just free this object */
1646d33b6beSLv Zheng 
1656d33b6beSLv Zheng 	if (cache->current_depth >= cache->max_depth) {
1666d33b6beSLv Zheng 		ACPI_FREE(object);
1676d33b6beSLv Zheng 		ACPI_MEM_TRACKING(cache->total_freed++);
1686d33b6beSLv Zheng 	}
1696d33b6beSLv Zheng 
1706d33b6beSLv Zheng 	/* Otherwise put this object back into the cache */
1716d33b6beSLv Zheng 
1726d33b6beSLv Zheng 	else {
1736d33b6beSLv Zheng 		status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
1746d33b6beSLv Zheng 		if (ACPI_FAILURE(status)) {
1756d33b6beSLv Zheng 			return (status);
1766d33b6beSLv Zheng 		}
1776d33b6beSLv Zheng 
1786d33b6beSLv Zheng 		/* Mark the object as cached */
1796d33b6beSLv Zheng 
1804fa4616eSBob Moore 		memset(object, 0xCA, cache->object_size);
1816d33b6beSLv Zheng 		ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED);
1826d33b6beSLv Zheng 
1836d33b6beSLv Zheng 		/* Put the object at the head of the cache list */
1846d33b6beSLv Zheng 
1851af89271SJung-uk Kim 		ACPI_SET_DESCRIPTOR_PTR(object, cache->list_head);
1866d33b6beSLv Zheng 		cache->list_head = object;
1876d33b6beSLv Zheng 		cache->current_depth++;
1886d33b6beSLv Zheng 
1896d33b6beSLv Zheng 		(void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
1906d33b6beSLv Zheng 	}
1916d33b6beSLv Zheng 
1926d33b6beSLv Zheng 	return (AE_OK);
1936d33b6beSLv Zheng }
1946d33b6beSLv Zheng 
1956d33b6beSLv Zheng /*******************************************************************************
1966d33b6beSLv Zheng  *
1976d33b6beSLv Zheng  * FUNCTION:    acpi_os_acquire_object
1986d33b6beSLv Zheng  *
1996d33b6beSLv Zheng  * PARAMETERS:  cache           - Handle to cache object
2006d33b6beSLv Zheng  *
2016d33b6beSLv Zheng  * RETURN:      the acquired object. NULL on error
2026d33b6beSLv Zheng  *
2036d33b6beSLv Zheng  * DESCRIPTION: Get an object from the specified cache. If cache is empty,
2046d33b6beSLv Zheng  *              the object is allocated.
2056d33b6beSLv Zheng  *
2066d33b6beSLv Zheng  ******************************************************************************/
2076d33b6beSLv Zheng 
acpi_os_acquire_object(struct acpi_memory_list * cache)2086d33b6beSLv Zheng void *acpi_os_acquire_object(struct acpi_memory_list *cache)
2096d33b6beSLv Zheng {
2106d33b6beSLv Zheng 	acpi_status status;
2116d33b6beSLv Zheng 	void *object;
2126d33b6beSLv Zheng 
2131e059e20SBob Moore 	ACPI_FUNCTION_TRACE(os_acquire_object);
2146d33b6beSLv Zheng 
2156d33b6beSLv Zheng 	if (!cache) {
2165076f005SBob Moore 		return_PTR(NULL);
2176d33b6beSLv Zheng 	}
2186d33b6beSLv Zheng 
2196d33b6beSLv Zheng 	status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
2206d33b6beSLv Zheng 	if (ACPI_FAILURE(status)) {
2215076f005SBob Moore 		return_PTR(NULL);
2226d33b6beSLv Zheng 	}
2236d33b6beSLv Zheng 
2246d33b6beSLv Zheng 	ACPI_MEM_TRACKING(cache->requests++);
2256d33b6beSLv Zheng 
2266d33b6beSLv Zheng 	/* Check the cache first */
2276d33b6beSLv Zheng 
2286d33b6beSLv Zheng 	if (cache->list_head) {
2296d33b6beSLv Zheng 
2306d33b6beSLv Zheng 		/* There is an object available, use it */
2316d33b6beSLv Zheng 
2326d33b6beSLv Zheng 		object = cache->list_head;
2331af89271SJung-uk Kim 		cache->list_head = ACPI_GET_DESCRIPTOR_PTR(object);
2346d33b6beSLv Zheng 
2356d33b6beSLv Zheng 		cache->current_depth--;
2366d33b6beSLv Zheng 
2376d33b6beSLv Zheng 		ACPI_MEM_TRACKING(cache->hits++);
2381ef63231SBob Moore 		ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC,
2391ef63231SBob Moore 				      "%s: Object %p from %s cache\n",
2401ef63231SBob Moore 				      ACPI_GET_FUNCTION_NAME, object,
2416d33b6beSLv Zheng 				      cache->list_name));
2426d33b6beSLv Zheng 
2436d33b6beSLv Zheng 		status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
2446d33b6beSLv Zheng 		if (ACPI_FAILURE(status)) {
2455076f005SBob Moore 			return_PTR(NULL);
2466d33b6beSLv Zheng 		}
2476d33b6beSLv Zheng 
2486d33b6beSLv Zheng 		/* Clear (zero) the previously used Object */
2496d33b6beSLv Zheng 
2504fa4616eSBob Moore 		memset(object, 0, cache->object_size);
2516d33b6beSLv Zheng 	} else {
2526d33b6beSLv Zheng 		/* The cache is empty, create a new object */
2536d33b6beSLv Zheng 
2546d33b6beSLv Zheng 		ACPI_MEM_TRACKING(cache->total_allocated++);
2556d33b6beSLv Zheng 
2566d33b6beSLv Zheng #ifdef ACPI_DBG_TRACK_ALLOCATIONS
2576d33b6beSLv Zheng 		if ((cache->total_allocated - cache->total_freed) >
2586d33b6beSLv Zheng 		    cache->max_occupied) {
2596d33b6beSLv Zheng 			cache->max_occupied =
2606d33b6beSLv Zheng 			    cache->total_allocated - cache->total_freed;
2616d33b6beSLv Zheng 		}
2626d33b6beSLv Zheng #endif
2636d33b6beSLv Zheng 
2646d33b6beSLv Zheng 		/* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
2656d33b6beSLv Zheng 
2666d33b6beSLv Zheng 		status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
2676d33b6beSLv Zheng 		if (ACPI_FAILURE(status)) {
2685076f005SBob Moore 			return_PTR(NULL);
2696d33b6beSLv Zheng 		}
2706d33b6beSLv Zheng 
2716d33b6beSLv Zheng 		object = ACPI_ALLOCATE_ZEROED(cache->object_size);
2726d33b6beSLv Zheng 		if (!object) {
2735076f005SBob Moore 			return_PTR(NULL);
2746d33b6beSLv Zheng 		}
2756d33b6beSLv Zheng 	}
2766d33b6beSLv Zheng 
2775076f005SBob Moore 	return_PTR(object);
2786d33b6beSLv Zheng }
2796d33b6beSLv Zheng #endif				/* ACPI_USE_LOCAL_CACHE */
280