diff options
Diffstat (limited to 'drivers/acpi/acpica/utcache.c')
| -rw-r--r-- | drivers/acpi/acpica/utcache.c | 323 | 
1 files changed, 323 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c new file mode 100644 index 00000000000..e1d40ed2639 --- /dev/null +++ b/drivers/acpi/acpica/utcache.c @@ -0,0 +1,323 @@ +/****************************************************************************** + * + * Module Name: utcache - local cache allocation routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" + +#define _COMPONENT          ACPI_UTILITIES +ACPI_MODULE_NAME("utcache") + +#ifdef ACPI_USE_LOCAL_CACHE +/******************************************************************************* + * + * FUNCTION:    acpi_os_create_cache + * + * PARAMETERS:  cache_name      - Ascii name for the cache + *              object_size     - Size of each cached object + *              max_depth       - Maximum depth of the cache (in objects) + *              return_cache    - Where the new cache object is returned + * + * RETURN:      Status + * + * DESCRIPTION: Create a cache object + * + ******************************************************************************/ +acpi_status +acpi_os_create_cache(char *cache_name, +		     u16 object_size, +		     u16 max_depth, struct acpi_memory_list ** return_cache) +{ +	struct acpi_memory_list *cache; + +	ACPI_FUNCTION_ENTRY(); + +	if (!cache_name || !return_cache || (object_size < 16)) { +		return (AE_BAD_PARAMETER); +	} + +	/* Create the cache object */ + +	cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); +	if (!cache) { +		return (AE_NO_MEMORY); +	} + +	/* Populate the cache object and return it */ + +	ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); +	cache->link_offset = 8; +	cache->list_name = cache_name; +	cache->object_size = object_size; +	cache->max_depth = max_depth; + +	*return_cache = cache; +	return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION:    acpi_os_purge_cache + * + * PARAMETERS:  cache           - Handle to cache object + * + * RETURN:      Status + * + * DESCRIPTION: Free all objects within the requested cache. + * + ******************************************************************************/ + +acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache) +{ +	char *next; +	acpi_status status; + +	ACPI_FUNCTION_ENTRY(); + +	if (!cache) { +		return (AE_BAD_PARAMETER); +	} + +	status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); +	if (ACPI_FAILURE(status)) { +		return (status); +	} + +	/* Walk the list of objects in this cache */ + +	while (cache->list_head) { + +		/* Delete and unlink one cached state object */ + +		next = *(ACPI_CAST_INDIRECT_PTR(char, +						&(((char *)cache-> +						   list_head)[cache-> +							      link_offset]))); +		ACPI_FREE(cache->list_head); + +		cache->list_head = next; +		cache->current_depth--; +	} + +	(void)acpi_ut_release_mutex(ACPI_MTX_CACHES); +	return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION:    acpi_os_delete_cache + * + * PARAMETERS:  cache           - Handle to cache object + * + * RETURN:      Status + * + * DESCRIPTION: Free all objects within the requested cache and delete the + *              cache object. + * + ******************************************************************************/ + +acpi_status acpi_os_delete_cache(struct acpi_memory_list * cache) +{ +	acpi_status status; + +	ACPI_FUNCTION_ENTRY(); + +	/* Purge all objects in the cache */ + +	status = acpi_os_purge_cache(cache); +	if (ACPI_FAILURE(status)) { +		return (status); +	} + +	/* Now we can delete the cache object */ + +	acpi_os_free(cache); +	return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION:    acpi_os_release_object + * + * PARAMETERS:  cache       - Handle to cache object + *              object      - The object to be released + * + * RETURN:      None + * + * DESCRIPTION: Release an object to the specified cache. If cache is full, + *              the object is deleted. + * + ******************************************************************************/ + +acpi_status +acpi_os_release_object(struct acpi_memory_list * cache, void *object) +{ +	acpi_status status; + +	ACPI_FUNCTION_ENTRY(); + +	if (!cache || !object) { +		return (AE_BAD_PARAMETER); +	} + +	/* If cache is full, just free this object */ + +	if (cache->current_depth >= cache->max_depth) { +		ACPI_FREE(object); +		ACPI_MEM_TRACKING(cache->total_freed++); +	} + +	/* Otherwise put this object back into the cache */ + +	else { +		status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); +		if (ACPI_FAILURE(status)) { +			return (status); +		} + +		/* Mark the object as cached */ + +		ACPI_MEMSET(object, 0xCA, cache->object_size); +		ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); + +		/* Put the object at the head of the cache list */ + +		*(ACPI_CAST_INDIRECT_PTR(char, +					 &(((char *)object)[cache-> +							    link_offset]))) = +		    cache->list_head; +		cache->list_head = object; +		cache->current_depth++; + +		(void)acpi_ut_release_mutex(ACPI_MTX_CACHES); +	} + +	return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION:    acpi_os_acquire_object + * + * PARAMETERS:  cache           - Handle to cache object + * + * RETURN:      the acquired object. NULL on error + * + * DESCRIPTION: Get an object from the specified cache. If cache is empty, + *              the object is allocated. + * + ******************************************************************************/ + +void *acpi_os_acquire_object(struct acpi_memory_list *cache) +{ +	acpi_status status; +	void *object; + +	ACPI_FUNCTION_NAME(os_acquire_object); + +	if (!cache) { +		return (NULL); +	} + +	status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); +	if (ACPI_FAILURE(status)) { +		return (NULL); +	} + +	ACPI_MEM_TRACKING(cache->requests++); + +	/* Check the cache first */ + +	if (cache->list_head) { + +		/* There is an object available, use it */ + +		object = cache->list_head; +		cache->list_head = *(ACPI_CAST_INDIRECT_PTR(char, +							    &(((char *) +							       object)[cache-> +								       link_offset]))); + +		cache->current_depth--; + +		ACPI_MEM_TRACKING(cache->hits++); +		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, +				  "Object %p from %s cache\n", object, +				  cache->list_name)); + +		status = acpi_ut_release_mutex(ACPI_MTX_CACHES); +		if (ACPI_FAILURE(status)) { +			return (NULL); +		} + +		/* Clear (zero) the previously used Object */ + +		ACPI_MEMSET(object, 0, cache->object_size); +	} else { +		/* The cache is empty, create a new object */ + +		ACPI_MEM_TRACKING(cache->total_allocated++); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +		if ((cache->total_allocated - cache->total_freed) > +		    cache->max_occupied) { +			cache->max_occupied = +			    cache->total_allocated - cache->total_freed; +		} +#endif + +		/* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ + +		status = acpi_ut_release_mutex(ACPI_MTX_CACHES); +		if (ACPI_FAILURE(status)) { +			return (NULL); +		} + +		object = ACPI_ALLOCATE_ZEROED(cache->object_size); +		if (!object) { +			return (NULL); +		} +	} + +	return (object); +} +#endif				/* ACPI_USE_LOCAL_CACHE */  |