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