1 /****************************************************************************** 2 * 3 * Module Name: utcache - local cache allocation routines 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2018, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include <acpi/acpi.h> 45 #include "accommon.h" 46 47 #define _COMPONENT ACPI_UTILITIES 48 ACPI_MODULE_NAME("utcache") 49 50 #ifdef ACPI_USE_LOCAL_CACHE 51 /******************************************************************************* 52 * 53 * FUNCTION: acpi_os_create_cache 54 * 55 * PARAMETERS: cache_name - Ascii name for the cache 56 * object_size - Size of each cached object 57 * max_depth - Maximum depth of the cache (in objects) 58 * return_cache - Where the new cache object is returned 59 * 60 * RETURN: Status 61 * 62 * DESCRIPTION: Create a cache object 63 * 64 ******************************************************************************/ 65 acpi_status 66 acpi_os_create_cache(char *cache_name, 67 u16 object_size, 68 u16 max_depth, struct acpi_memory_list **return_cache) 69 { 70 struct acpi_memory_list *cache; 71 72 ACPI_FUNCTION_ENTRY(); 73 74 if (!cache_name || !return_cache || !object_size) { 75 return (AE_BAD_PARAMETER); 76 } 77 78 /* Create the cache object */ 79 80 cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); 81 if (!cache) { 82 return (AE_NO_MEMORY); 83 } 84 85 /* Populate the cache object and return it */ 86 87 memset(cache, 0, sizeof(struct acpi_memory_list)); 88 cache->list_name = cache_name; 89 cache->object_size = object_size; 90 cache->max_depth = max_depth; 91 92 *return_cache = cache; 93 return (AE_OK); 94 } 95 96 /******************************************************************************* 97 * 98 * FUNCTION: acpi_os_purge_cache 99 * 100 * PARAMETERS: cache - Handle to cache object 101 * 102 * RETURN: Status 103 * 104 * DESCRIPTION: Free all objects within the requested cache. 105 * 106 ******************************************************************************/ 107 108 acpi_status acpi_os_purge_cache(struct acpi_memory_list *cache) 109 { 110 void *next; 111 acpi_status status; 112 113 ACPI_FUNCTION_ENTRY(); 114 115 if (!cache) { 116 return (AE_BAD_PARAMETER); 117 } 118 119 status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); 120 if (ACPI_FAILURE(status)) { 121 return (status); 122 } 123 124 /* Walk the list of objects in this cache */ 125 126 while (cache->list_head) { 127 128 /* Delete and unlink one cached state object */ 129 130 next = ACPI_GET_DESCRIPTOR_PTR(cache->list_head); 131 ACPI_FREE(cache->list_head); 132 133 cache->list_head = next; 134 cache->current_depth--; 135 } 136 137 (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); 138 return (AE_OK); 139 } 140 141 /******************************************************************************* 142 * 143 * FUNCTION: acpi_os_delete_cache 144 * 145 * PARAMETERS: cache - Handle to cache object 146 * 147 * RETURN: Status 148 * 149 * DESCRIPTION: Free all objects within the requested cache and delete the 150 * cache object. 151 * 152 ******************************************************************************/ 153 154 acpi_status acpi_os_delete_cache(struct acpi_memory_list *cache) 155 { 156 acpi_status status; 157 158 ACPI_FUNCTION_ENTRY(); 159 160 /* Purge all objects in the cache */ 161 162 status = acpi_os_purge_cache(cache); 163 if (ACPI_FAILURE(status)) { 164 return (status); 165 } 166 167 /* Now we can delete the cache object */ 168 169 acpi_os_free(cache); 170 return (AE_OK); 171 } 172 173 /******************************************************************************* 174 * 175 * FUNCTION: acpi_os_release_object 176 * 177 * PARAMETERS: cache - Handle to cache object 178 * object - The object to be released 179 * 180 * RETURN: None 181 * 182 * DESCRIPTION: Release an object to the specified cache. If cache is full, 183 * the object is deleted. 184 * 185 ******************************************************************************/ 186 187 acpi_status acpi_os_release_object(struct acpi_memory_list *cache, void *object) 188 { 189 acpi_status status; 190 191 ACPI_FUNCTION_ENTRY(); 192 193 if (!cache || !object) { 194 return (AE_BAD_PARAMETER); 195 } 196 197 /* If cache is full, just free this object */ 198 199 if (cache->current_depth >= cache->max_depth) { 200 ACPI_FREE(object); 201 ACPI_MEM_TRACKING(cache->total_freed++); 202 } 203 204 /* Otherwise put this object back into the cache */ 205 206 else { 207 status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); 208 if (ACPI_FAILURE(status)) { 209 return (status); 210 } 211 212 /* Mark the object as cached */ 213 214 memset(object, 0xCA, cache->object_size); 215 ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); 216 217 /* Put the object at the head of the cache list */ 218 219 ACPI_SET_DESCRIPTOR_PTR(object, cache->list_head); 220 cache->list_head = object; 221 cache->current_depth++; 222 223 (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); 224 } 225 226 return (AE_OK); 227 } 228 229 /******************************************************************************* 230 * 231 * FUNCTION: acpi_os_acquire_object 232 * 233 * PARAMETERS: cache - Handle to cache object 234 * 235 * RETURN: the acquired object. NULL on error 236 * 237 * DESCRIPTION: Get an object from the specified cache. If cache is empty, 238 * the object is allocated. 239 * 240 ******************************************************************************/ 241 242 void *acpi_os_acquire_object(struct acpi_memory_list *cache) 243 { 244 acpi_status status; 245 void *object; 246 247 ACPI_FUNCTION_TRACE(os_acquire_object); 248 249 if (!cache) { 250 return_PTR(NULL); 251 } 252 253 status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); 254 if (ACPI_FAILURE(status)) { 255 return_PTR(NULL); 256 } 257 258 ACPI_MEM_TRACKING(cache->requests++); 259 260 /* Check the cache first */ 261 262 if (cache->list_head) { 263 264 /* There is an object available, use it */ 265 266 object = cache->list_head; 267 cache->list_head = ACPI_GET_DESCRIPTOR_PTR(object); 268 269 cache->current_depth--; 270 271 ACPI_MEM_TRACKING(cache->hits++); 272 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 273 "Object %p from %s cache\n", object, 274 cache->list_name)); 275 276 status = acpi_ut_release_mutex(ACPI_MTX_CACHES); 277 if (ACPI_FAILURE(status)) { 278 return_PTR(NULL); 279 } 280 281 /* Clear (zero) the previously used Object */ 282 283 memset(object, 0, cache->object_size); 284 } else { 285 /* The cache is empty, create a new object */ 286 287 ACPI_MEM_TRACKING(cache->total_allocated++); 288 289 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 290 if ((cache->total_allocated - cache->total_freed) > 291 cache->max_occupied) { 292 cache->max_occupied = 293 cache->total_allocated - cache->total_freed; 294 } 295 #endif 296 297 /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ 298 299 status = acpi_ut_release_mutex(ACPI_MTX_CACHES); 300 if (ACPI_FAILURE(status)) { 301 return_PTR(NULL); 302 } 303 304 object = ACPI_ALLOCATE_ZEROED(cache->object_size); 305 if (!object) { 306 return_PTR(NULL); 307 } 308 } 309 310 return_PTR(object); 311 } 312 #endif /* ACPI_USE_LOCAL_CACHE */ 313