1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /******************************************************************************
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Module Name: utcache - local cache allocation routines
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (C) 2000 - 2020, Intel Corp.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun *****************************************************************************/
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <acpi/acpi.h>
11*4882a593Smuzhiyun #include "accommon.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #define _COMPONENT ACPI_UTILITIES
14*4882a593Smuzhiyun ACPI_MODULE_NAME("utcache")
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #ifdef ACPI_USE_LOCAL_CACHE
17*4882a593Smuzhiyun /*******************************************************************************
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * FUNCTION: acpi_os_create_cache
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun * PARAMETERS: cache_name - Ascii name for the cache
22*4882a593Smuzhiyun * object_size - Size of each cached object
23*4882a593Smuzhiyun * max_depth - Maximum depth of the cache (in objects)
24*4882a593Smuzhiyun * return_cache - Where the new cache object is returned
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * RETURN: Status
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * DESCRIPTION: Create a cache object
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun ******************************************************************************/
31*4882a593Smuzhiyun acpi_status
acpi_os_create_cache(char * cache_name,u16 object_size,u16 max_depth,struct acpi_memory_list ** return_cache)32*4882a593Smuzhiyun acpi_os_create_cache(char *cache_name,
33*4882a593Smuzhiyun u16 object_size,
34*4882a593Smuzhiyun u16 max_depth, struct acpi_memory_list **return_cache)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun struct acpi_memory_list *cache;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun ACPI_FUNCTION_ENTRY();
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun if (!cache_name || !return_cache || !object_size) {
41*4882a593Smuzhiyun return (AE_BAD_PARAMETER);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /* Create the cache object */
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun cache = acpi_os_allocate(sizeof(struct acpi_memory_list));
47*4882a593Smuzhiyun if (!cache) {
48*4882a593Smuzhiyun return (AE_NO_MEMORY);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* Populate the cache object and return it */
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun memset(cache, 0, sizeof(struct acpi_memory_list));
54*4882a593Smuzhiyun cache->list_name = cache_name;
55*4882a593Smuzhiyun cache->object_size = object_size;
56*4882a593Smuzhiyun cache->max_depth = max_depth;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun *return_cache = cache;
59*4882a593Smuzhiyun return (AE_OK);
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /*******************************************************************************
63*4882a593Smuzhiyun *
64*4882a593Smuzhiyun * FUNCTION: acpi_os_purge_cache
65*4882a593Smuzhiyun *
66*4882a593Smuzhiyun * PARAMETERS: cache - Handle to cache object
67*4882a593Smuzhiyun *
68*4882a593Smuzhiyun * RETURN: Status
69*4882a593Smuzhiyun *
70*4882a593Smuzhiyun * DESCRIPTION: Free all objects within the requested cache.
71*4882a593Smuzhiyun *
72*4882a593Smuzhiyun ******************************************************************************/
73*4882a593Smuzhiyun
acpi_os_purge_cache(struct acpi_memory_list * cache)74*4882a593Smuzhiyun acpi_status acpi_os_purge_cache(struct acpi_memory_list *cache)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun void *next;
77*4882a593Smuzhiyun acpi_status status;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun ACPI_FUNCTION_ENTRY();
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun if (!cache) {
82*4882a593Smuzhiyun return (AE_BAD_PARAMETER);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
86*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
87*4882a593Smuzhiyun return (status);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /* Walk the list of objects in this cache */
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun while (cache->list_head) {
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /* Delete and unlink one cached state object */
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun next = ACPI_GET_DESCRIPTOR_PTR(cache->list_head);
97*4882a593Smuzhiyun ACPI_FREE(cache->list_head);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun cache->list_head = next;
100*4882a593Smuzhiyun cache->current_depth--;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
104*4882a593Smuzhiyun return (AE_OK);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /*******************************************************************************
108*4882a593Smuzhiyun *
109*4882a593Smuzhiyun * FUNCTION: acpi_os_delete_cache
110*4882a593Smuzhiyun *
111*4882a593Smuzhiyun * PARAMETERS: cache - Handle to cache object
112*4882a593Smuzhiyun *
113*4882a593Smuzhiyun * RETURN: Status
114*4882a593Smuzhiyun *
115*4882a593Smuzhiyun * DESCRIPTION: Free all objects within the requested cache and delete the
116*4882a593Smuzhiyun * cache object.
117*4882a593Smuzhiyun *
118*4882a593Smuzhiyun ******************************************************************************/
119*4882a593Smuzhiyun
acpi_os_delete_cache(struct acpi_memory_list * cache)120*4882a593Smuzhiyun acpi_status acpi_os_delete_cache(struct acpi_memory_list *cache)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun acpi_status status;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun ACPI_FUNCTION_ENTRY();
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /* Purge all objects in the cache */
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun status = acpi_os_purge_cache(cache);
129*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
130*4882a593Smuzhiyun return (status);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /* Now we can delete the cache object */
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun acpi_os_free(cache);
136*4882a593Smuzhiyun return (AE_OK);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /*******************************************************************************
140*4882a593Smuzhiyun *
141*4882a593Smuzhiyun * FUNCTION: acpi_os_release_object
142*4882a593Smuzhiyun *
143*4882a593Smuzhiyun * PARAMETERS: cache - Handle to cache object
144*4882a593Smuzhiyun * object - The object to be released
145*4882a593Smuzhiyun *
146*4882a593Smuzhiyun * RETURN: None
147*4882a593Smuzhiyun *
148*4882a593Smuzhiyun * DESCRIPTION: Release an object to the specified cache. If cache is full,
149*4882a593Smuzhiyun * the object is deleted.
150*4882a593Smuzhiyun *
151*4882a593Smuzhiyun ******************************************************************************/
152*4882a593Smuzhiyun
acpi_os_release_object(struct acpi_memory_list * cache,void * object)153*4882a593Smuzhiyun acpi_status acpi_os_release_object(struct acpi_memory_list *cache, void *object)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun acpi_status status;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun ACPI_FUNCTION_ENTRY();
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun if (!cache || !object) {
160*4882a593Smuzhiyun return (AE_BAD_PARAMETER);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /* If cache is full, just free this object */
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun if (cache->current_depth >= cache->max_depth) {
166*4882a593Smuzhiyun ACPI_FREE(object);
167*4882a593Smuzhiyun ACPI_MEM_TRACKING(cache->total_freed++);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /* Otherwise put this object back into the cache */
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun else {
173*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
174*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
175*4882a593Smuzhiyun return (status);
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* Mark the object as cached */
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun memset(object, 0xCA, cache->object_size);
181*4882a593Smuzhiyun ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /* Put the object at the head of the cache list */
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun ACPI_SET_DESCRIPTOR_PTR(object, cache->list_head);
186*4882a593Smuzhiyun cache->list_head = object;
187*4882a593Smuzhiyun cache->current_depth++;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun return (AE_OK);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun /*******************************************************************************
196*4882a593Smuzhiyun *
197*4882a593Smuzhiyun * FUNCTION: acpi_os_acquire_object
198*4882a593Smuzhiyun *
199*4882a593Smuzhiyun * PARAMETERS: cache - Handle to cache object
200*4882a593Smuzhiyun *
201*4882a593Smuzhiyun * RETURN: the acquired object. NULL on error
202*4882a593Smuzhiyun *
203*4882a593Smuzhiyun * DESCRIPTION: Get an object from the specified cache. If cache is empty,
204*4882a593Smuzhiyun * the object is allocated.
205*4882a593Smuzhiyun *
206*4882a593Smuzhiyun ******************************************************************************/
207*4882a593Smuzhiyun
acpi_os_acquire_object(struct acpi_memory_list * cache)208*4882a593Smuzhiyun void *acpi_os_acquire_object(struct acpi_memory_list *cache)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun acpi_status status;
211*4882a593Smuzhiyun void *object;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(os_acquire_object);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (!cache) {
216*4882a593Smuzhiyun return_PTR(NULL);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
220*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
221*4882a593Smuzhiyun return_PTR(NULL);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun ACPI_MEM_TRACKING(cache->requests++);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /* Check the cache first */
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (cache->list_head) {
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun /* There is an object available, use it */
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun object = cache->list_head;
233*4882a593Smuzhiyun cache->list_head = ACPI_GET_DESCRIPTOR_PTR(object);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun cache->current_depth--;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun ACPI_MEM_TRACKING(cache->hits++);
238*4882a593Smuzhiyun ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC,
239*4882a593Smuzhiyun "%s: Object %p from %s cache\n",
240*4882a593Smuzhiyun ACPI_GET_FUNCTION_NAME, object,
241*4882a593Smuzhiyun cache->list_name));
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
244*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
245*4882a593Smuzhiyun return_PTR(NULL);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun /* Clear (zero) the previously used Object */
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun memset(object, 0, cache->object_size);
251*4882a593Smuzhiyun } else {
252*4882a593Smuzhiyun /* The cache is empty, create a new object */
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun ACPI_MEM_TRACKING(cache->total_allocated++);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun #ifdef ACPI_DBG_TRACK_ALLOCATIONS
257*4882a593Smuzhiyun if ((cache->total_allocated - cache->total_freed) >
258*4882a593Smuzhiyun cache->max_occupied) {
259*4882a593Smuzhiyun cache->max_occupied =
260*4882a593Smuzhiyun cache->total_allocated - cache->total_freed;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun #endif
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
267*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
268*4882a593Smuzhiyun return_PTR(NULL);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun object = ACPI_ALLOCATE_ZEROED(cache->object_size);
272*4882a593Smuzhiyun if (!object) {
273*4882a593Smuzhiyun return_PTR(NULL);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun return_PTR(object);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun #endif /* ACPI_USE_LOCAL_CACHE */
280