1/****************************************************************************** 2 * 3 * Module Name: utcache - local cache allocation routines 4 * 5 *****************************************************************************/ 6 7/* 8 * Copyright (C) 2000 - 2007, R. Byron Moore 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 46#define _COMPONENT ACPI_UTILITIES 47ACPI_MODULE_NAME("utcache") 48#ifdef ACPI_USE_LOCAL_CACHE 49/******************************************************************************* 50 * 51 * FUNCTION: acpi_os_create_cache 52 * 53 * PARAMETERS: cache_name - Ascii name for the cache 54 * object_size - Size of each cached object 55 * max_depth - Maximum depth of the cache (in objects) 56 * return_cache - Where the new cache object is returned 57 * 58 * RETURN: Status 59 * 60 * DESCRIPTION: Create a cache object 61 * 62 ******************************************************************************/ 63acpi_status 64acpi_os_create_cache(char *cache_name, 65 u16 object_size, 66 u16 max_depth, struct acpi_memory_list ** return_cache) 67{ 68 struct acpi_memory_list *cache; 69 70 ACPI_FUNCTION_ENTRY(); 71 72 if (!cache_name || !return_cache || (object_size < 16)) { 73 return (AE_BAD_PARAMETER); 74 } 75 76 /* Create the cache object */ 77 78 cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); 79 if (!cache) { 80 return (AE_NO_MEMORY); 81 } 82 83 /* Populate the cache object and return it */ 84 85 ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); 86 cache->link_offset = 8; 87 cache->list_name = cache_name; 88 cache->object_size = object_size; 89 cache->max_depth = max_depth; 90 91 *return_cache = cache; 92 return (AE_OK); 93} 94 95/******************************************************************************* 96 * 97 * FUNCTION: acpi_os_purge_cache 98 * 99 * PARAMETERS: Cache - Handle to cache object 100 * 101 * RETURN: Status 102 * 103 * DESCRIPTION: Free all objects within the requested cache. 104 * 105 ******************************************************************************/ 106 107acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache) 108{ 109 char *next; 110 111 ACPI_FUNCTION_ENTRY(); 112 113 if (!cache) { 114 return (AE_BAD_PARAMETER); 115 } 116 117 /* Walk the list of objects in this cache */ 118 119 while (cache->list_head) { 120 121 /* Delete and unlink one cached state object */ 122 123 next = *(ACPI_CAST_INDIRECT_PTR(char, 124 &(((char *)cache-> 125 list_head)[cache-> 126 link_offset]))); 127 ACPI_FREE(cache->list_head); 128 129 cache->list_head = next; 130 cache->current_depth--; 131 } 132 133 return (AE_OK); 134} 135 136/******************************************************************************* 137 * 138 * FUNCTION: acpi_os_delete_cache 139 * 140 * PARAMETERS: Cache - Handle to cache object 141 * 142 * RETURN: Status 143 * 144 * DESCRIPTION: Free all objects within the requested cache and delete the 145 * cache object. 146 * 147 ******************************************************************************/ 148 149acpi_status acpi_os_delete_cache(struct acpi_memory_list * cache) 150{ 151 acpi_status status; 152 153 ACPI_FUNCTION_ENTRY(); 154 155 /* Purge all objects in the cache */ 156 157 status = acpi_os_purge_cache(cache); 158 if (ACPI_FAILURE(status)) { 159 return (status); 160 } 161 162 /* Now we can delete the cache object */ 163 164 ACPI_FREE(cache); 165 return (AE_OK); 166} 167 168/******************************************************************************* 169 * 170 * FUNCTION: acpi_os_release_object 171 * 172 * PARAMETERS: Cache - Handle to cache object 173 * Object - The object to be released 174 * 175 * RETURN: None 176 * 177 * DESCRIPTION: Release an object to the specified cache. If cache is full, 178 * the object is deleted. 179 * 180 ******************************************************************************/ 181 182acpi_status 183acpi_os_release_object(struct acpi_memory_list * cache, void *object) 184{ 185 acpi_status status; 186 187 ACPI_FUNCTION_ENTRY(); 188 189 if (!cache || !object) { 190 return (AE_BAD_PARAMETER); 191 } 192 193 /* If cache is full, just free this object */ 194 195 if (cache->current_depth >= cache->max_depth) { 196 ACPI_FREE(object); 197 ACPI_MEM_TRACKING(cache->total_freed++); 198 } 199 200 /* Otherwise put this object back into the cache */ 201 202 else { 203 status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); 204 if (ACPI_FAILURE(status)) { 205 return (status); 206 } 207 208 /* Mark the object as cached */ 209 210 ACPI_MEMSET(object, 0xCA, cache->object_size); 211 ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); 212 213 /* Put the object at the head of the cache list */ 214 215 *(ACPI_CAST_INDIRECT_PTR(char, 216 &(((char *)object)[cache-> 217 link_offset]))) = 218 cache->list_head; 219 cache->list_head = object; 220 cache->current_depth++; 221 222 (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); 223 } 224 225 return (AE_OK); 226} 227 228/******************************************************************************* 229 * 230 * FUNCTION: acpi_os_acquire_object 231 * 232 * PARAMETERS: Cache - Handle to cache object 233 * 234 * RETURN: the acquired object. NULL on error 235 * 236 * DESCRIPTION: Get an object from the specified cache. If cache is empty, 237 * the object is allocated. 238 * 239 ******************************************************************************/ 240 241void *acpi_os_acquire_object(struct acpi_memory_list *cache) 242{ 243 acpi_status status; 244 void *object; 245 246 ACPI_FUNCTION_NAME(os_acquire_object); 247 248 if (!cache) { 249 return (NULL); 250 } 251 252 status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); 253 if (ACPI_FAILURE(status)) { 254 return (NULL); 255 } 256 257 ACPI_MEM_TRACKING(cache->requests++); 258 259 /* Check the cache first */ 260 261 if (cache->list_head) { 262 263 /* There is an object available, use it */ 264 265 object = cache->list_head; 266 cache->list_head = *(ACPI_CAST_INDIRECT_PTR(char, 267 &(((char *) 268 object)[cache-> 269 link_offset]))); 270 271 cache->current_depth--; 272 273 ACPI_MEM_TRACKING(cache->hits++); 274 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 275 "Object %p from %s cache\n", object, 276 cache->list_name)); 277 278 status = acpi_ut_release_mutex(ACPI_MTX_CACHES); 279 if (ACPI_FAILURE(status)) { 280 return (NULL); 281 } 282 283 /* Clear (zero) the previously used Object */ 284 285 ACPI_MEMSET(object, 0, cache->object_size); 286 } else { 287 /* The cache is empty, create a new object */ 288 289 ACPI_MEM_TRACKING(cache->total_allocated++); 290 291#ifdef ACPI_DBG_TRACK_ALLOCATIONS 292 if ((cache->total_allocated - cache->total_freed) > 293 cache->max_occupied) { 294 cache->max_occupied = 295 cache->total_allocated - cache->total_freed; 296 } 297#endif 298 299 /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ 300 301 status = acpi_ut_release_mutex(ACPI_MTX_CACHES); 302 if (ACPI_FAILURE(status)) { 303 return (NULL); 304 } 305 306 object = ACPI_ALLOCATE_ZEROED(cache->object_size); 307 if (!object) { 308 return (NULL); 309 } 310 } 311 312 return (object); 313} 314#endif /* ACPI_USE_LOCAL_CACHE */ 315