1151937Sjkim/******************************************************************************
2151937Sjkim *
3151937Sjkim * Module Name: utcache - local cache allocation routines
4151937Sjkim *
5151937Sjkim *****************************************************************************/
6151937Sjkim
7217365Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, 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
44193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
45193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
46151937Sjkim
47151937Sjkim#define _COMPONENT          ACPI_UTILITIES
48151937Sjkim        ACPI_MODULE_NAME    ("utcache")
49151937Sjkim
50151937Sjkim
51151937Sjkim#ifdef ACPI_USE_LOCAL_CACHE
52151937Sjkim/*******************************************************************************
53151937Sjkim *
54151937Sjkim * FUNCTION:    AcpiOsCreateCache
55151937Sjkim *
56151937Sjkim * PARAMETERS:  CacheName       - Ascii name for the cache
57151937Sjkim *              ObjectSize      - Size of each cached object
58151937Sjkim *              MaxDepth        - Maximum depth of the cache (in objects)
59151937Sjkim *              ReturnCache     - Where the new cache object is returned
60151937Sjkim *
61151937Sjkim * RETURN:      Status
62151937Sjkim *
63151937Sjkim * DESCRIPTION: Create a cache object
64151937Sjkim *
65151937Sjkim ******************************************************************************/
66151937Sjkim
67151937SjkimACPI_STATUS
68151937SjkimAcpiOsCreateCache (
69151937Sjkim    char                    *CacheName,
70151937Sjkim    UINT16                  ObjectSize,
71151937Sjkim    UINT16                  MaxDepth,
72151937Sjkim    ACPI_MEMORY_LIST        **ReturnCache)
73151937Sjkim{
74151937Sjkim    ACPI_MEMORY_LIST        *Cache;
75151937Sjkim
76151937Sjkim
77151937Sjkim    ACPI_FUNCTION_ENTRY ();
78151937Sjkim
79151937Sjkim
80151937Sjkim    if (!CacheName || !ReturnCache || (ObjectSize < 16))
81151937Sjkim    {
82151937Sjkim        return (AE_BAD_PARAMETER);
83151937Sjkim    }
84151937Sjkim
85151937Sjkim    /* Create the cache object */
86151937Sjkim
87151937Sjkim    Cache = AcpiOsAllocate (sizeof (ACPI_MEMORY_LIST));
88151937Sjkim    if (!Cache)
89151937Sjkim    {
90151937Sjkim        return (AE_NO_MEMORY);
91151937Sjkim    }
92151937Sjkim
93151937Sjkim    /* Populate the cache object and return it */
94151937Sjkim
95306536Sjkim    memset (Cache, 0, sizeof (ACPI_MEMORY_LIST));
96306536Sjkim    Cache->ListName = CacheName;
97151937Sjkim    Cache->ObjectSize = ObjectSize;
98306536Sjkim    Cache->MaxDepth = MaxDepth;
99151937Sjkim
100151937Sjkim    *ReturnCache = Cache;
101151937Sjkim    return (AE_OK);
102151937Sjkim}
103151937Sjkim
104151937Sjkim
105151937Sjkim/*******************************************************************************
106151937Sjkim *
107151937Sjkim * FUNCTION:    AcpiOsPurgeCache
108151937Sjkim *
109151937Sjkim * PARAMETERS:  Cache           - Handle to cache object
110151937Sjkim *
111151937Sjkim * RETURN:      Status
112151937Sjkim *
113151937Sjkim * DESCRIPTION: Free all objects within the requested cache.
114151937Sjkim *
115151937Sjkim ******************************************************************************/
116151937Sjkim
117151937SjkimACPI_STATUS
118151937SjkimAcpiOsPurgeCache (
119151937Sjkim    ACPI_MEMORY_LIST        *Cache)
120151937Sjkim{
121246040Sjkim    void                    *Next;
122193267Sjkim    ACPI_STATUS             Status;
123151937Sjkim
124151937Sjkim
125151937Sjkim    ACPI_FUNCTION_ENTRY ();
126151937Sjkim
127151937Sjkim
128151937Sjkim    if (!Cache)
129151937Sjkim    {
130151937Sjkim        return (AE_BAD_PARAMETER);
131151937Sjkim    }
132151937Sjkim
133193267Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
134193267Sjkim    if (ACPI_FAILURE (Status))
135193267Sjkim    {
136193267Sjkim        return (Status);
137193267Sjkim    }
138193267Sjkim
139151937Sjkim    /* Walk the list of objects in this cache */
140151937Sjkim
141151937Sjkim    while (Cache->ListHead)
142151937Sjkim    {
143151937Sjkim        /* Delete and unlink one cached state object */
144151937Sjkim
145246040Sjkim        Next = ACPI_GET_DESCRIPTOR_PTR (Cache->ListHead);
146167802Sjkim        ACPI_FREE (Cache->ListHead);
147151937Sjkim
148151937Sjkim        Cache->ListHead = Next;
149151937Sjkim        Cache->CurrentDepth--;
150151937Sjkim    }
151151937Sjkim
152193267Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES);
153151937Sjkim    return (AE_OK);
154151937Sjkim}
155151937Sjkim
156151937Sjkim
157151937Sjkim/*******************************************************************************
158151937Sjkim *
159151937Sjkim * FUNCTION:    AcpiOsDeleteCache
160151937Sjkim *
161151937Sjkim * PARAMETERS:  Cache           - Handle to cache object
162151937Sjkim *
163151937Sjkim * RETURN:      Status
164151937Sjkim *
165151937Sjkim * DESCRIPTION: Free all objects within the requested cache and delete the
166151937Sjkim *              cache object.
167151937Sjkim *
168151937Sjkim ******************************************************************************/
169151937Sjkim
170151937SjkimACPI_STATUS
171151937SjkimAcpiOsDeleteCache (
172151937Sjkim    ACPI_MEMORY_LIST        *Cache)
173151937Sjkim{
174151937Sjkim    ACPI_STATUS             Status;
175151937Sjkim
176151937Sjkim
177151937Sjkim    ACPI_FUNCTION_ENTRY ();
178151937Sjkim
179151937Sjkim
180151937Sjkim   /* Purge all objects in the cache */
181151937Sjkim
182151937Sjkim    Status = AcpiOsPurgeCache (Cache);
183151937Sjkim    if (ACPI_FAILURE (Status))
184151937Sjkim    {
185151937Sjkim        return (Status);
186151937Sjkim    }
187151937Sjkim
188151937Sjkim    /* Now we can delete the cache object */
189151937Sjkim
190151937Sjkim    AcpiOsFree (Cache);
191151937Sjkim    return (AE_OK);
192151937Sjkim}
193151937Sjkim
194151937Sjkim
195151937Sjkim/*******************************************************************************
196151937Sjkim *
197151937Sjkim * FUNCTION:    AcpiOsReleaseObject
198151937Sjkim *
199151937Sjkim * PARAMETERS:  Cache       - Handle to cache object
200151937Sjkim *              Object      - The object to be released
201151937Sjkim *
202151937Sjkim * RETURN:      None
203151937Sjkim *
204241973Sjkim * DESCRIPTION: Release an object to the specified cache. If cache is full,
205151937Sjkim *              the object is deleted.
206151937Sjkim *
207151937Sjkim ******************************************************************************/
208151937Sjkim
209151937SjkimACPI_STATUS
210151937SjkimAcpiOsReleaseObject (
211151937Sjkim    ACPI_MEMORY_LIST        *Cache,
212151937Sjkim    void                    *Object)
213151937Sjkim{
214151937Sjkim    ACPI_STATUS             Status;
215151937Sjkim
216151937Sjkim
217151937Sjkim    ACPI_FUNCTION_ENTRY ();
218151937Sjkim
219151937Sjkim
220151937Sjkim    if (!Cache || !Object)
221151937Sjkim    {
222151937Sjkim        return (AE_BAD_PARAMETER);
223151937Sjkim    }
224151937Sjkim
225151937Sjkim    /* If cache is full, just free this object */
226151937Sjkim
227151937Sjkim    if (Cache->CurrentDepth >= Cache->MaxDepth)
228151937Sjkim    {
229167802Sjkim        ACPI_FREE (Object);
230151937Sjkim        ACPI_MEM_TRACKING (Cache->TotalFreed++);
231151937Sjkim    }
232151937Sjkim
233151937Sjkim    /* Otherwise put this object back into the cache */
234151937Sjkim
235151937Sjkim    else
236151937Sjkim    {
237151937Sjkim        Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
238151937Sjkim        if (ACPI_FAILURE (Status))
239151937Sjkim        {
240151937Sjkim            return (Status);
241151937Sjkim        }
242151937Sjkim
243151937Sjkim        /* Mark the object as cached */
244151937Sjkim
245306536Sjkim        memset (Object, 0xCA, Cache->ObjectSize);
246151937Sjkim        ACPI_SET_DESCRIPTOR_TYPE (Object, ACPI_DESC_TYPE_CACHED);
247151937Sjkim
248151937Sjkim        /* Put the object at the head of the cache list */
249151937Sjkim
250246040Sjkim        ACPI_SET_DESCRIPTOR_PTR (Object, Cache->ListHead);
251151937Sjkim        Cache->ListHead = Object;
252151937Sjkim        Cache->CurrentDepth++;
253151937Sjkim
254151937Sjkim        (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES);
255151937Sjkim    }
256151937Sjkim
257151937Sjkim    return (AE_OK);
258151937Sjkim}
259151937Sjkim
260151937Sjkim
261151937Sjkim/*******************************************************************************
262151937Sjkim *
263151937Sjkim * FUNCTION:    AcpiOsAcquireObject
264151937Sjkim *
265151937Sjkim * PARAMETERS:  Cache           - Handle to cache object
266151937Sjkim *
267241973Sjkim * RETURN:      the acquired object. NULL on error
268151937Sjkim *
269241973Sjkim * DESCRIPTION: Get an object from the specified cache. If cache is empty,
270151937Sjkim *              the object is allocated.
271151937Sjkim *
272151937Sjkim ******************************************************************************/
273151937Sjkim
274151937Sjkimvoid *
275151937SjkimAcpiOsAcquireObject (
276151937Sjkim    ACPI_MEMORY_LIST        *Cache)
277151937Sjkim{
278151937Sjkim    ACPI_STATUS             Status;
279151937Sjkim    void                    *Object;
280151937Sjkim
281151937Sjkim
282306536Sjkim    ACPI_FUNCTION_TRACE (OsAcquireObject);
283151937Sjkim
284151937Sjkim
285151937Sjkim    if (!Cache)
286151937Sjkim    {
287281075Sdim        return_PTR (NULL);
288151937Sjkim    }
289151937Sjkim
290151937Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
291151937Sjkim    if (ACPI_FAILURE (Status))
292151937Sjkim    {
293281075Sdim        return_PTR (NULL);
294151937Sjkim    }
295151937Sjkim
296151937Sjkim    ACPI_MEM_TRACKING (Cache->Requests++);
297151937Sjkim
298151937Sjkim    /* Check the cache first */
299151937Sjkim
300151937Sjkim    if (Cache->ListHead)
301151937Sjkim    {
302151937Sjkim        /* There is an object available, use it */
303151937Sjkim
304151937Sjkim        Object = Cache->ListHead;
305246040Sjkim        Cache->ListHead = ACPI_GET_DESCRIPTOR_PTR (Object);
306151937Sjkim
307151937Sjkim        Cache->CurrentDepth--;
308151937Sjkim
309151937Sjkim        ACPI_MEM_TRACKING (Cache->Hits++);
310167802Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
311167802Sjkim            "Object %p from %s cache\n", Object, Cache->ListName));
312151937Sjkim
313151937Sjkim        Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES);
314151937Sjkim        if (ACPI_FAILURE (Status))
315151937Sjkim        {
316281075Sdim            return_PTR (NULL);
317151937Sjkim        }
318151937Sjkim
319151937Sjkim        /* Clear (zero) the previously used Object */
320151937Sjkim
321306536Sjkim        memset (Object, 0, Cache->ObjectSize);
322151937Sjkim    }
323151937Sjkim    else
324151937Sjkim    {
325151937Sjkim        /* The cache is empty, create a new object */
326151937Sjkim
327151937Sjkim        ACPI_MEM_TRACKING (Cache->TotalAllocated++);
328151937Sjkim
329167802Sjkim#ifdef ACPI_DBG_TRACK_ALLOCATIONS
330167802Sjkim        if ((Cache->TotalAllocated - Cache->TotalFreed) > Cache->MaxOccupied)
331167802Sjkim        {
332167802Sjkim            Cache->MaxOccupied = Cache->TotalAllocated - Cache->TotalFreed;
333167802Sjkim        }
334167802Sjkim#endif
335151937Sjkim
336167802Sjkim        /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
337167802Sjkim
338151937Sjkim        Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES);
339151937Sjkim        if (ACPI_FAILURE (Status))
340151937Sjkim        {
341281075Sdim            return_PTR (NULL);
342151937Sjkim        }
343151937Sjkim
344167802Sjkim        Object = ACPI_ALLOCATE_ZEROED (Cache->ObjectSize);
345151937Sjkim        if (!Object)
346151937Sjkim        {
347281075Sdim            return_PTR (NULL);
348151937Sjkim        }
349151937Sjkim    }
350151937Sjkim
351281075Sdim    return_PTR (Object);
352151937Sjkim}
353151937Sjkim#endif /* ACPI_USE_LOCAL_CACHE */
354