xref: /OK3568_Linux_fs/kernel/drivers/acpi/acpica/utcache.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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