1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /****************************************************************************** 3 * 4 * Module Name: utcache - local cache allocation routines 5 * 6 * Copyright (C) 2000 - 2019, Intel Corp. 7 * 8 *****************************************************************************/ 9 10 #include <acpi/acpi.h> 11 #include "accommon.h" 12 13 #define _COMPONENT ACPI_UTILITIES 14 ACPI_MODULE_NAME("utcache") 15 16 #ifdef ACPI_USE_LOCAL_CACHE 17 /******************************************************************************* 18 * 19 * FUNCTION: acpi_os_create_cache 20 * 21 * PARAMETERS: cache_name - Ascii name for the cache 22 * object_size - Size of each cached object 23 * max_depth - Maximum depth of the cache (in objects) 24 * return_cache - Where the new cache object is returned 25 * 26 * RETURN: Status 27 * 28 * DESCRIPTION: Create a cache object 29 * 30 ******************************************************************************/ 31 acpi_status 32 acpi_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_cache 65 * 66 * PARAMETERS: cache - Handle to cache object 67 * 68 * RETURN: Status 69 * 70 * DESCRIPTION: Free all objects within the requested cache. 71 * 72 ******************************************************************************/ 73 74 acpi_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_cache 110 * 111 * PARAMETERS: cache - Handle to cache object 112 * 113 * RETURN: Status 114 * 115 * DESCRIPTION: Free all objects within the requested cache and delete the 116 * cache object. 117 * 118 ******************************************************************************/ 119 120 acpi_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_object 142 * 143 * PARAMETERS: cache - Handle to cache object 144 * object - The object to be released 145 * 146 * RETURN: None 147 * 148 * DESCRIPTION: Release an object to the specified cache. If cache is full, 149 * the object is deleted. 150 * 151 ******************************************************************************/ 152 153 acpi_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_object 198 * 199 * PARAMETERS: cache - Handle to cache object 200 * 201 * RETURN: the acquired object. NULL on error 202 * 203 * DESCRIPTION: Get an object from the specified cache. If cache is empty, 204 * the object is allocated. 205 * 206 ******************************************************************************/ 207 208 void *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_ALLOCATIONS 257 if ((cache->total_allocated - cache->total_freed) > 258 cache->max_occupied) { 259 cache->max_occupied = 260 cache->total_allocated - cache->total_freed; 261 } 262 #endif 263 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