1 /****************************************************************************** 2 * 3 * Module Name: utcache - local cache allocation routines 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, 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 < 16)) { 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 188 acpi_os_release_object(struct acpi_memory_list * cache, void *object) 189 { 190 acpi_status status; 191 192 ACPI_FUNCTION_ENTRY(); 193 194 if (!cache || !object) { 195 return (AE_BAD_PARAMETER); 196 } 197 198 /* If cache is full, just free this object */ 199 200 if (cache->current_depth >= cache->max_depth) { 201 ACPI_FREE(object); 202 ACPI_MEM_TRACKING(cache->total_freed++); 203 } 204 205 /* Otherwise put this object back into the cache */ 206 207 else { 208 status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); 209 if (ACPI_FAILURE(status)) { 210 return (status); 211 } 212 213 /* Mark the object as cached */ 214 215 memset(object, 0xCA, cache->object_size); 216 ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); 217 218 /* Put the object at the head of the cache list */ 219 220 ACPI_SET_DESCRIPTOR_PTR(object, cache->list_head); 221 cache->list_head = object; 222 cache->current_depth++; 223 224 (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); 225 } 226 227 return (AE_OK); 228 } 229 230 /******************************************************************************* 231 * 232 * FUNCTION: acpi_os_acquire_object 233 * 234 * PARAMETERS: cache - Handle to cache object 235 * 236 * RETURN: the acquired object. NULL on error 237 * 238 * DESCRIPTION: Get an object from the specified cache. If cache is empty, 239 * the object is allocated. 240 * 241 ******************************************************************************/ 242 243 void *acpi_os_acquire_object(struct acpi_memory_list *cache) 244 { 245 acpi_status status; 246 void *object; 247 248 ACPI_FUNCTION_NAME(os_acquire_object); 249 250 if (!cache) { 251 return_PTR(NULL); 252 } 253 254 status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); 255 if (ACPI_FAILURE(status)) { 256 return_PTR(NULL); 257 } 258 259 ACPI_MEM_TRACKING(cache->requests++); 260 261 /* Check the cache first */ 262 263 if (cache->list_head) { 264 265 /* There is an object available, use it */ 266 267 object = cache->list_head; 268 cache->list_head = ACPI_GET_DESCRIPTOR_PTR(object); 269 270 cache->current_depth--; 271 272 ACPI_MEM_TRACKING(cache->hits++); 273 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 274 "Object %p from %s cache\n", object, 275 cache->list_name)); 276 277 status = acpi_ut_release_mutex(ACPI_MTX_CACHES); 278 if (ACPI_FAILURE(status)) { 279 return_PTR(NULL); 280 } 281 282 /* Clear (zero) the previously used Object */ 283 284 memset(object, 0, cache->object_size); 285 } else { 286 /* The cache is empty, create a new object */ 287 288 ACPI_MEM_TRACKING(cache->total_allocated++); 289 290 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 291 if ((cache->total_allocated - cache->total_freed) > 292 cache->max_occupied) { 293 cache->max_occupied = 294 cache->total_allocated - cache->total_freed; 295 } 296 #endif 297 298 /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ 299 300 status = acpi_ut_release_mutex(ACPI_MTX_CACHES); 301 if (ACPI_FAILURE(status)) { 302 return_PTR(NULL); 303 } 304 305 object = ACPI_ALLOCATE_ZEROED(cache->object_size); 306 if (!object) { 307 return_PTR(NULL); 308 } 309 } 310 311 return_PTR(object); 312 } 313 #endif /* ACPI_USE_LOCAL_CACHE */ 314