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