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