xref: /netbsd-src/sys/external/bsd/acpica/dist/utilities/utcache.c (revision 2c7d7e3ca2e4f0b675c6c58e614f6aede66c678e)
128c506b8Sjruoho /******************************************************************************
228c506b8Sjruoho  *
328c506b8Sjruoho  * Module Name: utcache - local cache allocation routines
428c506b8Sjruoho  *
528c506b8Sjruoho  *****************************************************************************/
628c506b8Sjruoho 
7159c4e26Sjruoho /*
8*2c7d7e3cSchristos  * Copyright (C) 2000 - 2023, Intel Corp.
928c506b8Sjruoho  * All rights reserved.
1028c506b8Sjruoho  *
11159c4e26Sjruoho  * Redistribution and use in source and binary forms, with or without
12159c4e26Sjruoho  * modification, are permitted provided that the following conditions
13159c4e26Sjruoho  * are met:
14159c4e26Sjruoho  * 1. Redistributions of source code must retain the above copyright
15159c4e26Sjruoho  *    notice, this list of conditions, and the following disclaimer,
16159c4e26Sjruoho  *    without modification.
17159c4e26Sjruoho  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18159c4e26Sjruoho  *    substantially similar to the "NO WARRANTY" disclaimer below
19159c4e26Sjruoho  *    ("Disclaimer") and any redistribution must be conditioned upon
20159c4e26Sjruoho  *    including a substantially similar Disclaimer requirement for further
21159c4e26Sjruoho  *    binary redistribution.
22159c4e26Sjruoho  * 3. Neither the names of the above-listed copyright holders nor the names
23159c4e26Sjruoho  *    of any contributors may be used to endorse or promote products derived
24159c4e26Sjruoho  *    from this software without specific prior written permission.
2528c506b8Sjruoho  *
26159c4e26Sjruoho  * Alternatively, this software may be distributed under the terms of the
27159c4e26Sjruoho  * GNU General Public License ("GPL") version 2 as published by the Free
28159c4e26Sjruoho  * Software Foundation.
2928c506b8Sjruoho  *
30159c4e26Sjruoho  * NO WARRANTY
31159c4e26Sjruoho  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32159c4e26Sjruoho  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3398244dcfSchristos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34159c4e26Sjruoho  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35159c4e26Sjruoho  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36159c4e26Sjruoho  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37159c4e26Sjruoho  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38159c4e26Sjruoho  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39159c4e26Sjruoho  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40159c4e26Sjruoho  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41159c4e26Sjruoho  * POSSIBILITY OF SUCH DAMAGES.
42159c4e26Sjruoho  */
4328c506b8Sjruoho 
4428c506b8Sjruoho #include "acpi.h"
4528c506b8Sjruoho #include "accommon.h"
4628c506b8Sjruoho 
4728c506b8Sjruoho #define _COMPONENT          ACPI_UTILITIES
4828c506b8Sjruoho         ACPI_MODULE_NAME    ("utcache")
4928c506b8Sjruoho 
5028c506b8Sjruoho 
5128c506b8Sjruoho #ifdef ACPI_USE_LOCAL_CACHE
5228c506b8Sjruoho /*******************************************************************************
5328c506b8Sjruoho  *
5428c506b8Sjruoho  * FUNCTION:    AcpiOsCreateCache
5528c506b8Sjruoho  *
5628c506b8Sjruoho  * PARAMETERS:  CacheName       - Ascii name for the cache
5728c506b8Sjruoho  *              ObjectSize      - Size of each cached object
5828c506b8Sjruoho  *              MaxDepth        - Maximum depth of the cache (in objects)
5928c506b8Sjruoho  *              ReturnCache     - Where the new cache object is returned
6028c506b8Sjruoho  *
6128c506b8Sjruoho  * RETURN:      Status
6228c506b8Sjruoho  *
6328c506b8Sjruoho  * DESCRIPTION: Create a cache object
6428c506b8Sjruoho  *
6528c506b8Sjruoho  ******************************************************************************/
6628c506b8Sjruoho 
6728c506b8Sjruoho ACPI_STATUS
AcpiOsCreateCache(const char * CacheName,UINT16 ObjectSize,UINT16 MaxDepth,ACPI_MEMORY_LIST ** ReturnCache)6828c506b8Sjruoho AcpiOsCreateCache (
69716c1ee0Sjruoho     const char              *CacheName,
7028c506b8Sjruoho     UINT16                  ObjectSize,
7128c506b8Sjruoho     UINT16                  MaxDepth,
7228c506b8Sjruoho     ACPI_MEMORY_LIST        **ReturnCache)
7328c506b8Sjruoho {
7428c506b8Sjruoho     ACPI_MEMORY_LIST        *Cache;
7528c506b8Sjruoho 
7628c506b8Sjruoho 
7728c506b8Sjruoho     ACPI_FUNCTION_ENTRY ();
7828c506b8Sjruoho 
7928c506b8Sjruoho 
808f1e17bdSchristos     if (!CacheName || !ReturnCache || !ObjectSize)
8128c506b8Sjruoho     {
8228c506b8Sjruoho         return (AE_BAD_PARAMETER);
8328c506b8Sjruoho     }
8428c506b8Sjruoho 
8528c506b8Sjruoho     /* Create the cache object */
8628c506b8Sjruoho 
8728c506b8Sjruoho     Cache = AcpiOsAllocate (sizeof (ACPI_MEMORY_LIST));
8828c506b8Sjruoho     if (!Cache)
8928c506b8Sjruoho     {
9028c506b8Sjruoho         return (AE_NO_MEMORY);
9128c506b8Sjruoho     }
9228c506b8Sjruoho 
9328c506b8Sjruoho     /* Populate the cache object and return it */
942489d3bdSrin 
959b9ee194Schristos     memset (Cache, 0, sizeof (ACPI_MEMORY_LIST));
96716c1ee0Sjruoho     Cache->ListName   = __UNCONST(CacheName);
9728c506b8Sjruoho     Cache->ObjectSize = ObjectSize;
9828c506b8Sjruoho     Cache->MaxDepth = MaxDepth;
9928c506b8Sjruoho 
10028c506b8Sjruoho     *ReturnCache = Cache;
10128c506b8Sjruoho     return (AE_OK);
10228c506b8Sjruoho }
10328c506b8Sjruoho 
10428c506b8Sjruoho 
10528c506b8Sjruoho /*******************************************************************************
10628c506b8Sjruoho  *
10728c506b8Sjruoho  * FUNCTION:    AcpiOsPurgeCache
10828c506b8Sjruoho  *
10928c506b8Sjruoho  * PARAMETERS:  Cache           - Handle to cache object
11028c506b8Sjruoho  *
11128c506b8Sjruoho  * RETURN:      Status
11228c506b8Sjruoho  *
11328c506b8Sjruoho  * DESCRIPTION: Free all objects within the requested cache.
11428c506b8Sjruoho  *
11528c506b8Sjruoho  ******************************************************************************/
11628c506b8Sjruoho 
11728c506b8Sjruoho ACPI_STATUS
AcpiOsPurgeCache(ACPI_MEMORY_LIST * Cache)11828c506b8Sjruoho AcpiOsPurgeCache (
11928c506b8Sjruoho     ACPI_MEMORY_LIST        *Cache)
12028c506b8Sjruoho {
121a2c051a9Schristos     void                    *Next;
12228c506b8Sjruoho     ACPI_STATUS             Status;
12328c506b8Sjruoho 
12428c506b8Sjruoho 
12528c506b8Sjruoho     ACPI_FUNCTION_ENTRY ();
12628c506b8Sjruoho 
12728c506b8Sjruoho 
12828c506b8Sjruoho     if (!Cache)
12928c506b8Sjruoho     {
13028c506b8Sjruoho         return (AE_BAD_PARAMETER);
13128c506b8Sjruoho     }
13228c506b8Sjruoho 
13328c506b8Sjruoho     Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
13428c506b8Sjruoho     if (ACPI_FAILURE (Status))
13528c506b8Sjruoho     {
13628c506b8Sjruoho         return (Status);
13728c506b8Sjruoho     }
13828c506b8Sjruoho 
13928c506b8Sjruoho     /* Walk the list of objects in this cache */
14028c506b8Sjruoho 
14128c506b8Sjruoho     while (Cache->ListHead)
14228c506b8Sjruoho     {
14328c506b8Sjruoho         /* Delete and unlink one cached state object */
14428c506b8Sjruoho 
145a2c051a9Schristos         Next = ACPI_GET_DESCRIPTOR_PTR (Cache->ListHead);
14628c506b8Sjruoho         ACPI_FREE (Cache->ListHead);
14728c506b8Sjruoho 
14828c506b8Sjruoho         Cache->ListHead = Next;
14928c506b8Sjruoho         Cache->CurrentDepth--;
15028c506b8Sjruoho     }
15128c506b8Sjruoho 
15228c506b8Sjruoho     (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES);
15328c506b8Sjruoho     return (AE_OK);
15428c506b8Sjruoho }
15528c506b8Sjruoho 
15628c506b8Sjruoho 
15728c506b8Sjruoho /*******************************************************************************
15828c506b8Sjruoho  *
15928c506b8Sjruoho  * FUNCTION:    AcpiOsDeleteCache
16028c506b8Sjruoho  *
16128c506b8Sjruoho  * PARAMETERS:  Cache           - Handle to cache object
16228c506b8Sjruoho  *
16328c506b8Sjruoho  * RETURN:      Status
16428c506b8Sjruoho  *
16528c506b8Sjruoho  * DESCRIPTION: Free all objects within the requested cache and delete the
16628c506b8Sjruoho  *              cache object.
16728c506b8Sjruoho  *
16828c506b8Sjruoho  ******************************************************************************/
16928c506b8Sjruoho 
17028c506b8Sjruoho ACPI_STATUS
AcpiOsDeleteCache(ACPI_MEMORY_LIST * Cache)17128c506b8Sjruoho AcpiOsDeleteCache (
17228c506b8Sjruoho     ACPI_MEMORY_LIST        *Cache)
17328c506b8Sjruoho {
17428c506b8Sjruoho     ACPI_STATUS             Status;
17528c506b8Sjruoho 
17628c506b8Sjruoho 
17728c506b8Sjruoho     ACPI_FUNCTION_ENTRY ();
17828c506b8Sjruoho 
17928c506b8Sjruoho 
18028c506b8Sjruoho    /* Purge all objects in the cache */
18128c506b8Sjruoho 
18228c506b8Sjruoho     Status = AcpiOsPurgeCache (Cache);
18328c506b8Sjruoho     if (ACPI_FAILURE (Status))
18428c506b8Sjruoho     {
18528c506b8Sjruoho         return (Status);
18628c506b8Sjruoho     }
18728c506b8Sjruoho 
18828c506b8Sjruoho     /* Now we can delete the cache object */
18928c506b8Sjruoho 
19028c506b8Sjruoho     AcpiOsFree (Cache);
19128c506b8Sjruoho     return (AE_OK);
19228c506b8Sjruoho }
19328c506b8Sjruoho 
19428c506b8Sjruoho 
19528c506b8Sjruoho /*******************************************************************************
19628c506b8Sjruoho  *
19728c506b8Sjruoho  * FUNCTION:    AcpiOsReleaseObject
19828c506b8Sjruoho  *
19928c506b8Sjruoho  * PARAMETERS:  Cache       - Handle to cache object
20028c506b8Sjruoho  *              Object      - The object to be released
20128c506b8Sjruoho  *
20228c506b8Sjruoho  * RETURN:      None
20328c506b8Sjruoho  *
20428c506b8Sjruoho  * DESCRIPTION: Release an object to the specified cache. If cache is full,
20528c506b8Sjruoho  *              the object is deleted.
20628c506b8Sjruoho  *
20728c506b8Sjruoho  ******************************************************************************/
20828c506b8Sjruoho 
20928c506b8Sjruoho ACPI_STATUS
AcpiOsReleaseObject(ACPI_MEMORY_LIST * Cache,void * Object)21028c506b8Sjruoho AcpiOsReleaseObject (
21128c506b8Sjruoho     ACPI_MEMORY_LIST        *Cache,
21228c506b8Sjruoho     void                    *Object)
21328c506b8Sjruoho {
21428c506b8Sjruoho     ACPI_STATUS             Status;
21528c506b8Sjruoho 
21628c506b8Sjruoho 
21728c506b8Sjruoho     ACPI_FUNCTION_ENTRY ();
21828c506b8Sjruoho 
21928c506b8Sjruoho 
22028c506b8Sjruoho     if (!Cache || !Object)
22128c506b8Sjruoho     {
22228c506b8Sjruoho         return (AE_BAD_PARAMETER);
22328c506b8Sjruoho     }
22428c506b8Sjruoho 
22528c506b8Sjruoho     /* If cache is full, just free this object */
22628c506b8Sjruoho 
22728c506b8Sjruoho     if (Cache->CurrentDepth >= Cache->MaxDepth)
22828c506b8Sjruoho     {
22928c506b8Sjruoho         ACPI_FREE (Object);
23028c506b8Sjruoho         ACPI_MEM_TRACKING (Cache->TotalFreed++);
23128c506b8Sjruoho     }
23228c506b8Sjruoho 
23328c506b8Sjruoho     /* Otherwise put this object back into the cache */
23428c506b8Sjruoho 
23528c506b8Sjruoho     else
23628c506b8Sjruoho     {
23728c506b8Sjruoho         Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
23828c506b8Sjruoho         if (ACPI_FAILURE (Status))
23928c506b8Sjruoho         {
24028c506b8Sjruoho             return (Status);
24128c506b8Sjruoho         }
24228c506b8Sjruoho 
24328c506b8Sjruoho         /* Mark the object as cached */
24428c506b8Sjruoho 
2459b9ee194Schristos         memset (Object, 0xCA, Cache->ObjectSize);
24628c506b8Sjruoho         ACPI_SET_DESCRIPTOR_TYPE (Object, ACPI_DESC_TYPE_CACHED);
24728c506b8Sjruoho 
24828c506b8Sjruoho         /* Put the object at the head of the cache list */
24928c506b8Sjruoho 
250a2c051a9Schristos         ACPI_SET_DESCRIPTOR_PTR (Object, Cache->ListHead);
25128c506b8Sjruoho         Cache->ListHead = Object;
25228c506b8Sjruoho         Cache->CurrentDepth++;
25328c506b8Sjruoho 
25428c506b8Sjruoho         (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES);
25528c506b8Sjruoho     }
25628c506b8Sjruoho 
25728c506b8Sjruoho     return (AE_OK);
25828c506b8Sjruoho }
25928c506b8Sjruoho 
26028c506b8Sjruoho 
26128c506b8Sjruoho /*******************************************************************************
26228c506b8Sjruoho  *
26328c506b8Sjruoho  * FUNCTION:    AcpiOsAcquireObject
26428c506b8Sjruoho  *
26528c506b8Sjruoho  * PARAMETERS:  Cache           - Handle to cache object
26628c506b8Sjruoho  *
26728c506b8Sjruoho  * RETURN:      the acquired object. NULL on error
26828c506b8Sjruoho  *
26928c506b8Sjruoho  * DESCRIPTION: Get an object from the specified cache. If cache is empty,
27028c506b8Sjruoho  *              the object is allocated.
27128c506b8Sjruoho  *
27228c506b8Sjruoho  ******************************************************************************/
27328c506b8Sjruoho 
27428c506b8Sjruoho void *
AcpiOsAcquireObject(ACPI_MEMORY_LIST * Cache)27528c506b8Sjruoho AcpiOsAcquireObject (
27628c506b8Sjruoho     ACPI_MEMORY_LIST        *Cache)
27728c506b8Sjruoho {
27828c506b8Sjruoho     ACPI_STATUS             Status;
27928c506b8Sjruoho     void                    *Object;
28028c506b8Sjruoho 
28128c506b8Sjruoho 
28249c2f1f4Schristos     ACPI_FUNCTION_TRACE (OsAcquireObject);
28328c506b8Sjruoho 
28428c506b8Sjruoho 
28528c506b8Sjruoho     if (!Cache)
28628c506b8Sjruoho     {
287a2c051a9Schristos         return_PTR (NULL);
28828c506b8Sjruoho     }
28928c506b8Sjruoho 
29028c506b8Sjruoho     Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
29128c506b8Sjruoho     if (ACPI_FAILURE (Status))
29228c506b8Sjruoho     {
293a2c051a9Schristos         return_PTR (NULL);
29428c506b8Sjruoho     }
29528c506b8Sjruoho 
29628c506b8Sjruoho     ACPI_MEM_TRACKING (Cache->Requests++);
29728c506b8Sjruoho 
29828c506b8Sjruoho     /* Check the cache first */
29928c506b8Sjruoho 
30028c506b8Sjruoho     if (Cache->ListHead)
30128c506b8Sjruoho     {
30228c506b8Sjruoho         /* There is an object available, use it */
30328c506b8Sjruoho 
30428c506b8Sjruoho         Object = Cache->ListHead;
305a2c051a9Schristos         Cache->ListHead = ACPI_GET_DESCRIPTOR_PTR (Object);
30628c506b8Sjruoho 
30728c506b8Sjruoho         Cache->CurrentDepth--;
30828c506b8Sjruoho 
30928c506b8Sjruoho         ACPI_MEM_TRACKING (Cache->Hits++);
310f45f09e8Schristos         ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC,
311f45f09e8Schristos             "%s: Object %p from %s cache\n",
312f45f09e8Schristos             ACPI_GET_FUNCTION_NAME, Object, Cache->ListName));
31328c506b8Sjruoho 
31428c506b8Sjruoho         Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES);
31528c506b8Sjruoho         if (ACPI_FAILURE (Status))
31628c506b8Sjruoho         {
317a2c051a9Schristos             return_PTR (NULL);
31828c506b8Sjruoho         }
31928c506b8Sjruoho 
32028c506b8Sjruoho         /* Clear (zero) the previously used Object */
32128c506b8Sjruoho 
3229b9ee194Schristos         memset (Object, 0, Cache->ObjectSize);
32328c506b8Sjruoho     }
32428c506b8Sjruoho     else
32528c506b8Sjruoho     {
32628c506b8Sjruoho         /* The cache is empty, create a new object */
32728c506b8Sjruoho 
32828c506b8Sjruoho         ACPI_MEM_TRACKING (Cache->TotalAllocated++);
32928c506b8Sjruoho 
33028c506b8Sjruoho #ifdef ACPI_DBG_TRACK_ALLOCATIONS
33128c506b8Sjruoho         if ((Cache->TotalAllocated - Cache->TotalFreed) > Cache->MaxOccupied)
33228c506b8Sjruoho         {
33328c506b8Sjruoho             Cache->MaxOccupied = Cache->TotalAllocated - Cache->TotalFreed;
33428c506b8Sjruoho         }
33528c506b8Sjruoho #endif
33628c506b8Sjruoho 
33728c506b8Sjruoho         /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
33828c506b8Sjruoho 
33928c506b8Sjruoho         Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES);
34028c506b8Sjruoho         if (ACPI_FAILURE (Status))
34128c506b8Sjruoho         {
342a2c051a9Schristos             return_PTR (NULL);
34328c506b8Sjruoho         }
34428c506b8Sjruoho 
34528c506b8Sjruoho         Object = ACPI_ALLOCATE_ZEROED (Cache->ObjectSize);
34628c506b8Sjruoho         if (!Object)
34728c506b8Sjruoho         {
348a2c051a9Schristos             return_PTR (NULL);
34928c506b8Sjruoho         }
35028c506b8Sjruoho     }
35128c506b8Sjruoho 
352a2c051a9Schristos     return_PTR (Object);
35328c506b8Sjruoho }
35428c506b8Sjruoho #endif /* ACPI_USE_LOCAL_CACHE */
355