1151937Sjkim/******************************************************************************
2151937Sjkim *
3151937Sjkim * Module Name: utcache - local cache allocation routines
4151937Sjkim *
5151937Sjkim *****************************************************************************/
6151937Sjkim
7217365Sjkim/*
8245582Sjkim * Copyright (C) 2000 - 2013, Intel Corp.
9151937Sjkim * All rights reserved.
10151937Sjkim *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
25151937Sjkim *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
29151937Sjkim *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
43151937Sjkim
44151937Sjkim#define __UTCACHE_C__
45151937Sjkim
46193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
47193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
48151937Sjkim
49151937Sjkim#define _COMPONENT          ACPI_UTILITIES
50151937Sjkim        ACPI_MODULE_NAME    ("utcache")
51151937Sjkim
52151937Sjkim
53151937Sjkim#ifdef ACPI_USE_LOCAL_CACHE
54151937Sjkim/*******************************************************************************
55151937Sjkim *
56151937Sjkim * FUNCTION:    AcpiOsCreateCache
57151937Sjkim *
58151937Sjkim * PARAMETERS:  CacheName       - Ascii name for the cache
59151937Sjkim *              ObjectSize      - Size of each cached object
60151937Sjkim *              MaxDepth        - Maximum depth of the cache (in objects)
61151937Sjkim *              ReturnCache     - Where the new cache object is returned
62151937Sjkim *
63151937Sjkim * RETURN:      Status
64151937Sjkim *
65151937Sjkim * DESCRIPTION: Create a cache object
66151937Sjkim *
67151937Sjkim ******************************************************************************/
68151937Sjkim
69151937SjkimACPI_STATUS
70151937SjkimAcpiOsCreateCache (
71151937Sjkim    char                    *CacheName,
72151937Sjkim    UINT16                  ObjectSize,
73151937Sjkim    UINT16                  MaxDepth,
74151937Sjkim    ACPI_MEMORY_LIST        **ReturnCache)
75151937Sjkim{
76151937Sjkim    ACPI_MEMORY_LIST        *Cache;
77151937Sjkim
78151937Sjkim
79151937Sjkim    ACPI_FUNCTION_ENTRY ();
80151937Sjkim
81151937Sjkim
82151937Sjkim    if (!CacheName || !ReturnCache || (ObjectSize < 16))
83151937Sjkim    {
84151937Sjkim        return (AE_BAD_PARAMETER);
85151937Sjkim    }
86151937Sjkim
87151937Sjkim    /* Create the cache object */
88151937Sjkim
89151937Sjkim    Cache = AcpiOsAllocate (sizeof (ACPI_MEMORY_LIST));
90151937Sjkim    if (!Cache)
91151937Sjkim    {
92151937Sjkim        return (AE_NO_MEMORY);
93151937Sjkim    }
94151937Sjkim
95151937Sjkim    /* Populate the cache object and return it */
96151937Sjkim
97151937Sjkim    ACPI_MEMSET (Cache, 0, sizeof (ACPI_MEMORY_LIST));
98151937Sjkim    Cache->ListName   = CacheName;
99151937Sjkim    Cache->ObjectSize = ObjectSize;
100151937Sjkim    Cache->MaxDepth   = MaxDepth;
101151937Sjkim
102151937Sjkim    *ReturnCache = Cache;
103151937Sjkim    return (AE_OK);
104151937Sjkim}
105151937Sjkim
106151937Sjkim
107151937Sjkim/*******************************************************************************
108151937Sjkim *
109151937Sjkim * FUNCTION:    AcpiOsPurgeCache
110151937Sjkim *
111151937Sjkim * PARAMETERS:  Cache           - Handle to cache object
112151937Sjkim *
113151937Sjkim * RETURN:      Status
114151937Sjkim *
115151937Sjkim * DESCRIPTION: Free all objects within the requested cache.
116151937Sjkim *
117151937Sjkim ******************************************************************************/
118151937Sjkim
119151937SjkimACPI_STATUS
120151937SjkimAcpiOsPurgeCache (
121151937Sjkim    ACPI_MEMORY_LIST        *Cache)
122151937Sjkim{
123246040Sjkim    void                    *Next;
124193267Sjkim    ACPI_STATUS             Status;
125151937Sjkim
126151937Sjkim
127151937Sjkim    ACPI_FUNCTION_ENTRY ();
128151937Sjkim
129151937Sjkim
130151937Sjkim    if (!Cache)
131151937Sjkim    {
132151937Sjkim        return (AE_BAD_PARAMETER);
133151937Sjkim    }
134151937Sjkim
135193267Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
136193267Sjkim    if (ACPI_FAILURE (Status))
137193267Sjkim    {
138193267Sjkim        return (Status);
139193267Sjkim    }
140193267Sjkim
141151937Sjkim    /* Walk the list of objects in this cache */
142151937Sjkim
143151937Sjkim    while (Cache->ListHead)
144151937Sjkim    {
145151937Sjkim        /* Delete and unlink one cached state object */
146151937Sjkim
147246040Sjkim        Next = ACPI_GET_DESCRIPTOR_PTR (Cache->ListHead);
148167802Sjkim        ACPI_FREE (Cache->ListHead);
149151937Sjkim
150151937Sjkim        Cache->ListHead = Next;
151151937Sjkim        Cache->CurrentDepth--;
152151937Sjkim    }
153151937Sjkim
154193267Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES);
155151937Sjkim    return (AE_OK);
156151937Sjkim}
157151937Sjkim
158151937Sjkim
159151937Sjkim/*******************************************************************************
160151937Sjkim *
161151937Sjkim * FUNCTION:    AcpiOsDeleteCache
162151937Sjkim *
163151937Sjkim * PARAMETERS:  Cache           - Handle to cache object
164151937Sjkim *
165151937Sjkim * RETURN:      Status
166151937Sjkim *
167151937Sjkim * DESCRIPTION: Free all objects within the requested cache and delete the
168151937Sjkim *              cache object.
169151937Sjkim *
170151937Sjkim ******************************************************************************/
171151937Sjkim
172151937SjkimACPI_STATUS
173151937SjkimAcpiOsDeleteCache (
174151937Sjkim    ACPI_MEMORY_LIST        *Cache)
175151937Sjkim{
176151937Sjkim    ACPI_STATUS             Status;
177151937Sjkim
178151937Sjkim
179151937Sjkim    ACPI_FUNCTION_ENTRY ();
180151937Sjkim
181151937Sjkim
182151937Sjkim   /* Purge all objects in the cache */
183151937Sjkim
184151937Sjkim    Status = AcpiOsPurgeCache (Cache);
185151937Sjkim    if (ACPI_FAILURE (Status))
186151937Sjkim    {
187151937Sjkim        return (Status);
188151937Sjkim    }
189151937Sjkim
190151937Sjkim    /* Now we can delete the cache object */
191151937Sjkim
192151937Sjkim    AcpiOsFree (Cache);
193151937Sjkim    return (AE_OK);
194151937Sjkim}
195151937Sjkim
196151937Sjkim
197151937Sjkim/*******************************************************************************
198151937Sjkim *
199151937Sjkim * FUNCTION:    AcpiOsReleaseObject
200151937Sjkim *
201151937Sjkim * PARAMETERS:  Cache       - Handle to cache object
202151937Sjkim *              Object      - The object to be released
203151937Sjkim *
204151937Sjkim * RETURN:      None
205151937Sjkim *
206241973Sjkim * DESCRIPTION: Release an object to the specified cache. If cache is full,
207151937Sjkim *              the object is deleted.
208151937Sjkim *
209151937Sjkim ******************************************************************************/
210151937Sjkim
211151937SjkimACPI_STATUS
212151937SjkimAcpiOsReleaseObject (
213151937Sjkim    ACPI_MEMORY_LIST        *Cache,
214151937Sjkim    void                    *Object)
215151937Sjkim{
216151937Sjkim    ACPI_STATUS             Status;
217151937Sjkim
218151937Sjkim
219151937Sjkim    ACPI_FUNCTION_ENTRY ();
220151937Sjkim
221151937Sjkim
222151937Sjkim    if (!Cache || !Object)
223151937Sjkim    {
224151937Sjkim        return (AE_BAD_PARAMETER);
225151937Sjkim    }
226151937Sjkim
227151937Sjkim    /* If cache is full, just free this object */
228151937Sjkim
229151937Sjkim    if (Cache->CurrentDepth >= Cache->MaxDepth)
230151937Sjkim    {
231167802Sjkim        ACPI_FREE (Object);
232151937Sjkim        ACPI_MEM_TRACKING (Cache->TotalFreed++);
233151937Sjkim    }
234151937Sjkim
235151937Sjkim    /* Otherwise put this object back into the cache */
236151937Sjkim
237151937Sjkim    else
238151937Sjkim    {
239151937Sjkim        Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
240151937Sjkim        if (ACPI_FAILURE (Status))
241151937Sjkim        {
242151937Sjkim            return (Status);
243151937Sjkim        }
244151937Sjkim
245151937Sjkim        /* Mark the object as cached */
246151937Sjkim
247151937Sjkim        ACPI_MEMSET (Object, 0xCA, Cache->ObjectSize);
248151937Sjkim        ACPI_SET_DESCRIPTOR_TYPE (Object, ACPI_DESC_TYPE_CACHED);
249151937Sjkim
250151937Sjkim        /* Put the object at the head of the cache list */
251151937Sjkim
252246040Sjkim        ACPI_SET_DESCRIPTOR_PTR (Object, Cache->ListHead);
253151937Sjkim        Cache->ListHead = Object;
254151937Sjkim        Cache->CurrentDepth++;
255151937Sjkim
256151937Sjkim        (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES);
257151937Sjkim    }
258151937Sjkim
259151937Sjkim    return (AE_OK);
260151937Sjkim}
261151937Sjkim
262151937Sjkim
263151937Sjkim/*******************************************************************************
264151937Sjkim *
265151937Sjkim * FUNCTION:    AcpiOsAcquireObject
266151937Sjkim *
267151937Sjkim * PARAMETERS:  Cache           - Handle to cache object
268151937Sjkim *
269241973Sjkim * RETURN:      the acquired object. NULL on error
270151937Sjkim *
271241973Sjkim * DESCRIPTION: Get an object from the specified cache. If cache is empty,
272151937Sjkim *              the object is allocated.
273151937Sjkim *
274151937Sjkim ******************************************************************************/
275151937Sjkim
276151937Sjkimvoid *
277151937SjkimAcpiOsAcquireObject (
278151937Sjkim    ACPI_MEMORY_LIST        *Cache)
279151937Sjkim{
280151937Sjkim    ACPI_STATUS             Status;
281151937Sjkim    void                    *Object;
282151937Sjkim
283151937Sjkim
284167802Sjkim    ACPI_FUNCTION_NAME (OsAcquireObject);
285151937Sjkim
286151937Sjkim
287151937Sjkim    if (!Cache)
288151937Sjkim    {
289151937Sjkim        return (NULL);
290151937Sjkim    }
291151937Sjkim
292151937Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
293151937Sjkim    if (ACPI_FAILURE (Status))
294151937Sjkim    {
295151937Sjkim        return (NULL);
296151937Sjkim    }
297151937Sjkim
298151937Sjkim    ACPI_MEM_TRACKING (Cache->Requests++);
299151937Sjkim
300151937Sjkim    /* Check the cache first */
301151937Sjkim
302151937Sjkim    if (Cache->ListHead)
303151937Sjkim    {
304151937Sjkim        /* There is an object available, use it */
305151937Sjkim
306151937Sjkim        Object = Cache->ListHead;
307246040Sjkim        Cache->ListHead = ACPI_GET_DESCRIPTOR_PTR (Object);
308151937Sjkim
309151937Sjkim        Cache->CurrentDepth--;
310151937Sjkim
311151937Sjkim        ACPI_MEM_TRACKING (Cache->Hits++);
312167802Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
313167802Sjkim            "Object %p from %s cache\n", Object, Cache->ListName));
314151937Sjkim
315151937Sjkim        Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES);
316151937Sjkim        if (ACPI_FAILURE (Status))
317151937Sjkim        {
318151937Sjkim            return (NULL);
319151937Sjkim        }
320151937Sjkim
321151937Sjkim        /* Clear (zero) the previously used Object */
322151937Sjkim
323151937Sjkim        ACPI_MEMSET (Object, 0, Cache->ObjectSize);
324151937Sjkim    }
325151937Sjkim    else
326151937Sjkim    {
327151937Sjkim        /* The cache is empty, create a new object */
328151937Sjkim
329151937Sjkim        ACPI_MEM_TRACKING (Cache->TotalAllocated++);
330151937Sjkim
331167802Sjkim#ifdef ACPI_DBG_TRACK_ALLOCATIONS
332167802Sjkim        if ((Cache->TotalAllocated - Cache->TotalFreed) > Cache->MaxOccupied)
333167802Sjkim        {
334167802Sjkim            Cache->MaxOccupied = Cache->TotalAllocated - Cache->TotalFreed;
335167802Sjkim        }
336167802Sjkim#endif
337151937Sjkim
338167802Sjkim        /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
339167802Sjkim
340151937Sjkim        Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES);
341151937Sjkim        if (ACPI_FAILURE (Status))
342151937Sjkim        {
343151937Sjkim            return (NULL);
344151937Sjkim        }
345151937Sjkim
346167802Sjkim        Object = ACPI_ALLOCATE_ZEROED (Cache->ObjectSize);
347151937Sjkim        if (!Object)
348151937Sjkim        {
349151937Sjkim            return (NULL);
350151937Sjkim        }
351151937Sjkim    }
352151937Sjkim
353151937Sjkim    return (Object);
354151937Sjkim}
355151937Sjkim#endif /* ACPI_USE_LOCAL_CACHE */
356