linux/drivers/acpi/acpica/utcache.c
<<
>>
Prefs
   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 - 2021, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12
  13#define _COMPONENT          ACPI_UTILITIES
  14ACPI_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 ******************************************************************************/
  31acpi_status
  32acpi_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
  74acpi_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
 120acpi_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
 153acpi_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
 208void *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 */
 280