1 /****************************************************************************** 2 * 3 * Module Name: utcache - local cache allocation routines 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2017, 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.h" 45 #include "accommon.h" 46 47 #define _COMPONENT ACPI_UTILITIES 48 ACPI_MODULE_NAME ("utcache") 49 50 51 #ifdef ACPI_USE_LOCAL_CACHE 52 /******************************************************************************* 53 * 54 * FUNCTION: AcpiOsCreateCache 55 * 56 * PARAMETERS: CacheName - Ascii name for the cache 57 * ObjectSize - Size of each cached object 58 * MaxDepth - Maximum depth of the cache (in objects) 59 * ReturnCache - Where the new cache object is returned 60 * 61 * RETURN: Status 62 * 63 * DESCRIPTION: Create a cache object 64 * 65 ******************************************************************************/ 66 67 ACPI_STATUS 68 AcpiOsCreateCache ( 69 char *CacheName, 70 UINT16 ObjectSize, 71 UINT16 MaxDepth, 72 ACPI_MEMORY_LIST **ReturnCache) 73 { 74 ACPI_MEMORY_LIST *Cache; 75 76 77 ACPI_FUNCTION_ENTRY (); 78 79 80 if (!CacheName || !ReturnCache || !ObjectSize) 81 { 82 return (AE_BAD_PARAMETER); 83 } 84 85 /* Create the cache object */ 86 87 Cache = AcpiOsAllocate (sizeof (ACPI_MEMORY_LIST)); 88 if (!Cache) 89 { 90 return (AE_NO_MEMORY); 91 } 92 93 /* Populate the cache object and return it */ 94 95 memset (Cache, 0, sizeof (ACPI_MEMORY_LIST)); 96 Cache->ListName = CacheName; 97 Cache->ObjectSize = ObjectSize; 98 Cache->MaxDepth = MaxDepth; 99 100 *ReturnCache = Cache; 101 return (AE_OK); 102 } 103 104 105 /******************************************************************************* 106 * 107 * FUNCTION: AcpiOsPurgeCache 108 * 109 * PARAMETERS: Cache - Handle to cache object 110 * 111 * RETURN: Status 112 * 113 * DESCRIPTION: Free all objects within the requested cache. 114 * 115 ******************************************************************************/ 116 117 ACPI_STATUS 118 AcpiOsPurgeCache ( 119 ACPI_MEMORY_LIST *Cache) 120 { 121 void *Next; 122 ACPI_STATUS Status; 123 124 125 ACPI_FUNCTION_ENTRY (); 126 127 128 if (!Cache) 129 { 130 return (AE_BAD_PARAMETER); 131 } 132 133 Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES); 134 if (ACPI_FAILURE (Status)) 135 { 136 return (Status); 137 } 138 139 /* Walk the list of objects in this cache */ 140 141 while (Cache->ListHead) 142 { 143 /* Delete and unlink one cached state object */ 144 145 Next = ACPI_GET_DESCRIPTOR_PTR (Cache->ListHead); 146 ACPI_FREE (Cache->ListHead); 147 148 Cache->ListHead = Next; 149 Cache->CurrentDepth--; 150 } 151 152 (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES); 153 return (AE_OK); 154 } 155 156 157 /******************************************************************************* 158 * 159 * FUNCTION: AcpiOsDeleteCache 160 * 161 * PARAMETERS: Cache - Handle to cache object 162 * 163 * RETURN: Status 164 * 165 * DESCRIPTION: Free all objects within the requested cache and delete the 166 * cache object. 167 * 168 ******************************************************************************/ 169 170 ACPI_STATUS 171 AcpiOsDeleteCache ( 172 ACPI_MEMORY_LIST *Cache) 173 { 174 ACPI_STATUS Status; 175 176 177 ACPI_FUNCTION_ENTRY (); 178 179 180 /* Purge all objects in the cache */ 181 182 Status = AcpiOsPurgeCache (Cache); 183 if (ACPI_FAILURE (Status)) 184 { 185 return (Status); 186 } 187 188 /* Now we can delete the cache object */ 189 190 AcpiOsFree (Cache); 191 return (AE_OK); 192 } 193 194 195 /******************************************************************************* 196 * 197 * FUNCTION: AcpiOsReleaseObject 198 * 199 * PARAMETERS: Cache - Handle to cache object 200 * Object - The object to be released 201 * 202 * RETURN: None 203 * 204 * DESCRIPTION: Release an object to the specified cache. If cache is full, 205 * the object is deleted. 206 * 207 ******************************************************************************/ 208 209 ACPI_STATUS 210 AcpiOsReleaseObject ( 211 ACPI_MEMORY_LIST *Cache, 212 void *Object) 213 { 214 ACPI_STATUS Status; 215 216 217 ACPI_FUNCTION_ENTRY (); 218 219 220 if (!Cache || !Object) 221 { 222 return (AE_BAD_PARAMETER); 223 } 224 225 /* If cache is full, just free this object */ 226 227 if (Cache->CurrentDepth >= Cache->MaxDepth) 228 { 229 ACPI_FREE (Object); 230 ACPI_MEM_TRACKING (Cache->TotalFreed++); 231 } 232 233 /* Otherwise put this object back into the cache */ 234 235 else 236 { 237 Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES); 238 if (ACPI_FAILURE (Status)) 239 { 240 return (Status); 241 } 242 243 /* Mark the object as cached */ 244 245 memset (Object, 0xCA, Cache->ObjectSize); 246 ACPI_SET_DESCRIPTOR_TYPE (Object, ACPI_DESC_TYPE_CACHED); 247 248 /* Put the object at the head of the cache list */ 249 250 ACPI_SET_DESCRIPTOR_PTR (Object, Cache->ListHead); 251 Cache->ListHead = Object; 252 Cache->CurrentDepth++; 253 254 (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES); 255 } 256 257 return (AE_OK); 258 } 259 260 261 /******************************************************************************* 262 * 263 * FUNCTION: AcpiOsAcquireObject 264 * 265 * PARAMETERS: Cache - Handle to cache object 266 * 267 * RETURN: the acquired object. NULL on error 268 * 269 * DESCRIPTION: Get an object from the specified cache. If cache is empty, 270 * the object is allocated. 271 * 272 ******************************************************************************/ 273 274 void * 275 AcpiOsAcquireObject ( 276 ACPI_MEMORY_LIST *Cache) 277 { 278 ACPI_STATUS Status; 279 void *Object; 280 281 282 ACPI_FUNCTION_TRACE (OsAcquireObject); 283 284 285 if (!Cache) 286 { 287 return_PTR (NULL); 288 } 289 290 Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES); 291 if (ACPI_FAILURE (Status)) 292 { 293 return_PTR (NULL); 294 } 295 296 ACPI_MEM_TRACKING (Cache->Requests++); 297 298 /* Check the cache first */ 299 300 if (Cache->ListHead) 301 { 302 /* There is an object available, use it */ 303 304 Object = Cache->ListHead; 305 Cache->ListHead = ACPI_GET_DESCRIPTOR_PTR (Object); 306 307 Cache->CurrentDepth--; 308 309 ACPI_MEM_TRACKING (Cache->Hits++); 310 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 311 "Object %p from %s cache\n", Object, Cache->ListName)); 312 313 Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES); 314 if (ACPI_FAILURE (Status)) 315 { 316 return_PTR (NULL); 317 } 318 319 /* Clear (zero) the previously used Object */ 320 321 memset (Object, 0, Cache->ObjectSize); 322 } 323 else 324 { 325 /* The cache is empty, create a new object */ 326 327 ACPI_MEM_TRACKING (Cache->TotalAllocated++); 328 329 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 330 if ((Cache->TotalAllocated - Cache->TotalFreed) > Cache->MaxOccupied) 331 { 332 Cache->MaxOccupied = Cache->TotalAllocated - Cache->TotalFreed; 333 } 334 #endif 335 336 /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ 337 338 Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES); 339 if (ACPI_FAILURE (Status)) 340 { 341 return_PTR (NULL); 342 } 343 344 Object = ACPI_ALLOCATE_ZEROED (Cache->ObjectSize); 345 if (!Object) 346 { 347 return_PTR (NULL); 348 } 349 } 350 351 return_PTR (Object); 352 } 353 #endif /* ACPI_USE_LOCAL_CACHE */ 354