280 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: utcache - local cache allocation routines5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12 13#define _COMPONENT ACPI_UTILITIES14ACPI_MODULE_NAME("utcache")15 16#ifdef ACPI_USE_LOCAL_CACHE17/*******************************************************************************18 *19 * FUNCTION: acpi_os_create_cache20 *21 * PARAMETERS: cache_name - Ascii name for the cache22 * object_size - Size of each cached object23 * max_depth - Maximum depth of the cache (in objects)24 * return_cache - Where the new cache object is returned25 *26 * RETURN: Status27 *28 * DESCRIPTION: Create a cache object29 *30 ******************************************************************************/31acpi_status32acpi_os_create_cache(char *cache_name,33 u16 object_size,34 u16 max_depth, struct acpi_memory_list **return_cache)35{36 struct acpi_memory_list *cache;37 38 ACPI_FUNCTION_ENTRY();39 40 if (!cache_name || !return_cache || !object_size) {41 return (AE_BAD_PARAMETER);42 }43 44 /* Create the cache object */45 46 cache = acpi_os_allocate(sizeof(struct acpi_memory_list));47 if (!cache) {48 return (AE_NO_MEMORY);49 }50 51 /* Populate the cache object and return it */52 53 memset(cache, 0, sizeof(struct acpi_memory_list));54 cache->list_name = cache_name;55 cache->object_size = object_size;56 cache->max_depth = max_depth;57 58 *return_cache = cache;59 return (AE_OK);60}61 62/*******************************************************************************63 *64 * FUNCTION: acpi_os_purge_cache65 *66 * PARAMETERS: cache - Handle to cache object67 *68 * RETURN: Status69 *70 * DESCRIPTION: Free all objects within the requested cache.71 *72 ******************************************************************************/73 74acpi_status acpi_os_purge_cache(struct acpi_memory_list *cache)75{76 void *next;77 acpi_status status;78 79 ACPI_FUNCTION_ENTRY();80 81 if (!cache) {82 return (AE_BAD_PARAMETER);83 }84 85 status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);86 if (ACPI_FAILURE(status)) {87 return (status);88 }89 90 /* Walk the list of objects in this cache */91 92 while (cache->list_head) {93 94 /* Delete and unlink one cached state object */95 96 next = ACPI_GET_DESCRIPTOR_PTR(cache->list_head);97 ACPI_FREE(cache->list_head);98 99 cache->list_head = next;100 cache->current_depth--;101 }102 103 (void)acpi_ut_release_mutex(ACPI_MTX_CACHES);104 return (AE_OK);105}106 107/*******************************************************************************108 *109 * FUNCTION: acpi_os_delete_cache110 *111 * PARAMETERS: cache - Handle to cache object112 *113 * RETURN: Status114 *115 * DESCRIPTION: Free all objects within the requested cache and delete the116 * cache object.117 *118 ******************************************************************************/119 120acpi_status acpi_os_delete_cache(struct acpi_memory_list *cache)121{122 acpi_status status;123 124 ACPI_FUNCTION_ENTRY();125 126 /* Purge all objects in the cache */127 128 status = acpi_os_purge_cache(cache);129 if (ACPI_FAILURE(status)) {130 return (status);131 }132 133 /* Now we can delete the cache object */134 135 acpi_os_free(cache);136 return (AE_OK);137}138 139/*******************************************************************************140 *141 * FUNCTION: acpi_os_release_object142 *143 * PARAMETERS: cache - Handle to cache object144 * object - The object to be released145 *146 * RETURN: None147 *148 * DESCRIPTION: Release an object to the specified cache. If cache is full,149 * the object is deleted.150 *151 ******************************************************************************/152 153acpi_status acpi_os_release_object(struct acpi_memory_list *cache, void *object)154{155 acpi_status status;156 157 ACPI_FUNCTION_ENTRY();158 159 if (!cache || !object) {160 return (AE_BAD_PARAMETER);161 }162 163 /* If cache is full, just free this object */164 165 if (cache->current_depth >= cache->max_depth) {166 ACPI_FREE(object);167 ACPI_MEM_TRACKING(cache->total_freed++);168 }169 170 /* Otherwise put this object back into the cache */171 172 else {173 status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);174 if (ACPI_FAILURE(status)) {175 return (status);176 }177 178 /* Mark the object as cached */179 180 memset(object, 0xCA, cache->object_size);181 ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED);182 183 /* Put the object at the head of the cache list */184 185 ACPI_SET_DESCRIPTOR_PTR(object, cache->list_head);186 cache->list_head = object;187 cache->current_depth++;188 189 (void)acpi_ut_release_mutex(ACPI_MTX_CACHES);190 }191 192 return (AE_OK);193}194 195/*******************************************************************************196 *197 * FUNCTION: acpi_os_acquire_object198 *199 * PARAMETERS: cache - Handle to cache object200 *201 * RETURN: the acquired object. NULL on error202 *203 * DESCRIPTION: Get an object from the specified cache. If cache is empty,204 * the object is allocated.205 *206 ******************************************************************************/207 208void *acpi_os_acquire_object(struct acpi_memory_list *cache)209{210 acpi_status status;211 void *object;212 213 ACPI_FUNCTION_TRACE(os_acquire_object);214 215 if (!cache) {216 return_PTR(NULL);217 }218 219 status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);220 if (ACPI_FAILURE(status)) {221 return_PTR(NULL);222 }223 224 ACPI_MEM_TRACKING(cache->requests++);225 226 /* Check the cache first */227 228 if (cache->list_head) {229 230 /* There is an object available, use it */231 232 object = cache->list_head;233 cache->list_head = ACPI_GET_DESCRIPTOR_PTR(object);234 235 cache->current_depth--;236 237 ACPI_MEM_TRACKING(cache->hits++);238 ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC,239 "%s: Object %p from %s cache\n",240 ACPI_GET_FUNCTION_NAME, object,241 cache->list_name));242 243 status = acpi_ut_release_mutex(ACPI_MTX_CACHES);244 if (ACPI_FAILURE(status)) {245 return_PTR(NULL);246 }247 248 /* Clear (zero) the previously used Object */249 250 memset(object, 0, cache->object_size);251 } else {252 /* The cache is empty, create a new object */253 254 ACPI_MEM_TRACKING(cache->total_allocated++);255 256#ifdef ACPI_DBG_TRACK_ALLOCATIONS257 if ((cache->total_allocated - cache->total_freed) >258 cache->max_occupied) {259 cache->max_occupied =260 cache->total_allocated - cache->total_freed;261 }262#endif263 264 /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */265 266 status = acpi_ut_release_mutex(ACPI_MTX_CACHES);267 if (ACPI_FAILURE(status)) {268 return_PTR(NULL);269 }270 271 object = ACPI_ALLOCATE_ZEROED(cache->object_size);272 if (!object) {273 return_PTR(NULL);274 }275 }276 277 return_PTR(object);278}279#endif /* ACPI_USE_LOCAL_CACHE */280