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