310 lines
11 KiB
C
310 lines
11 KiB
C
|
/*
|
||
|
* Copyright (C) 2010-2011 ARM Limited. All rights reserved.
|
||
|
*
|
||
|
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
|
||
|
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
|
||
|
*
|
||
|
* A copy of the licence is included with the program, and can also be obtained from Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
*/
|
||
|
|
||
|
#include "mali_kernel_common.h"
|
||
|
#include "mali_kernel_core.h"
|
||
|
#include "mali_kernel_memory_engine.h"
|
||
|
#include "mali_osk.h"
|
||
|
|
||
|
typedef struct os_allocation
|
||
|
{
|
||
|
u32 num_pages;
|
||
|
u32 offset_start;
|
||
|
mali_allocation_engine * engine;
|
||
|
mali_memory_allocation * descriptor;
|
||
|
} os_allocation;
|
||
|
|
||
|
typedef struct os_allocator
|
||
|
{
|
||
|
_mali_osk_lock_t *mutex;
|
||
|
|
||
|
/**
|
||
|
* Maximum number of pages to allocate from the OS
|
||
|
*/
|
||
|
u32 num_pages_max;
|
||
|
|
||
|
/**
|
||
|
* Number of pages allocated from the OS
|
||
|
*/
|
||
|
u32 num_pages_allocated;
|
||
|
|
||
|
/** CPU Usage adjustment (add to mali physical address to get cpu physical address) */
|
||
|
u32 cpu_usage_adjust;
|
||
|
} os_allocator;
|
||
|
|
||
|
static mali_physical_memory_allocation_result os_allocator_allocate(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info);
|
||
|
static mali_physical_memory_allocation_result os_allocator_allocate_page_table_block(void * ctx, mali_page_table_block * block);
|
||
|
static void os_allocator_release(void * ctx, void * handle);
|
||
|
static void os_allocator_page_table_block_release( mali_page_table_block *page_table_block );
|
||
|
static void os_allocator_destroy(mali_physical_memory_allocator * allocator);
|
||
|
|
||
|
mali_physical_memory_allocator * mali_os_allocator_create(u32 max_allocation, u32 cpu_usage_adjust, const char *name)
|
||
|
{
|
||
|
mali_physical_memory_allocator * allocator;
|
||
|
os_allocator * info;
|
||
|
|
||
|
max_allocation = (max_allocation + _MALI_OSK_CPU_PAGE_SIZE-1) & ~(_MALI_OSK_CPU_PAGE_SIZE-1);
|
||
|
|
||
|
MALI_DEBUG_PRINT(2, ("Mali OS memory allocator created with max allocation size of 0x%X bytes, cpu_usage_adjust 0x%08X\n", max_allocation, cpu_usage_adjust));
|
||
|
|
||
|
allocator = _mali_osk_malloc(sizeof(mali_physical_memory_allocator));
|
||
|
if (NULL != allocator)
|
||
|
{
|
||
|
info = _mali_osk_malloc(sizeof(os_allocator));
|
||
|
if (NULL != info)
|
||
|
{
|
||
|
info->num_pages_max = max_allocation / _MALI_OSK_CPU_PAGE_SIZE;
|
||
|
info->num_pages_allocated = 0;
|
||
|
info->cpu_usage_adjust = cpu_usage_adjust;
|
||
|
|
||
|
info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE | _MALI_OSK_LOCKFLAG_ORDERED, 0, 106);
|
||
|
if (NULL != info->mutex)
|
||
|
{
|
||
|
allocator->allocate = os_allocator_allocate;
|
||
|
allocator->allocate_page_table_block = os_allocator_allocate_page_table_block;
|
||
|
allocator->destroy = os_allocator_destroy;
|
||
|
allocator->ctx = info;
|
||
|
allocator->name = name;
|
||
|
|
||
|
return allocator;
|
||
|
}
|
||
|
_mali_osk_free(info);
|
||
|
}
|
||
|
_mali_osk_free(allocator);
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static void os_allocator_destroy(mali_physical_memory_allocator * allocator)
|
||
|
{
|
||
|
os_allocator * info;
|
||
|
MALI_DEBUG_ASSERT_POINTER(allocator);
|
||
|
MALI_DEBUG_ASSERT_POINTER(allocator->ctx);
|
||
|
info = (os_allocator*)allocator->ctx;
|
||
|
_mali_osk_lock_term(info->mutex);
|
||
|
_mali_osk_free(info);
|
||
|
_mali_osk_free(allocator);
|
||
|
}
|
||
|
|
||
|
static mali_physical_memory_allocation_result os_allocator_allocate(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info)
|
||
|
{
|
||
|
mali_physical_memory_allocation_result result = MALI_MEM_ALLOC_NONE;
|
||
|
u32 left;
|
||
|
os_allocator * info;
|
||
|
os_allocation * allocation;
|
||
|
int pages_allocated = 0;
|
||
|
_mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER(ctx);
|
||
|
MALI_DEBUG_ASSERT_POINTER(engine);
|
||
|
MALI_DEBUG_ASSERT_POINTER(descriptor);
|
||
|
MALI_DEBUG_ASSERT_POINTER(offset);
|
||
|
MALI_DEBUG_ASSERT_POINTER(alloc_info);
|
||
|
|
||
|
info = (os_allocator*)ctx;
|
||
|
left = descriptor->size - *offset;
|
||
|
|
||
|
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW)) return MALI_MEM_ALLOC_INTERNAL_FAILURE;
|
||
|
|
||
|
/** @note this code may not work on Linux, or may require a more complex Linux implementation */
|
||
|
allocation = _mali_osk_malloc(sizeof(os_allocation));
|
||
|
if (NULL != allocation)
|
||
|
{
|
||
|
u32 os_mem_max_usage = info->num_pages_max * _MALI_OSK_CPU_PAGE_SIZE;
|
||
|
allocation->offset_start = *offset;
|
||
|
allocation->num_pages = ((left + _MALI_OSK_CPU_PAGE_SIZE - 1) & ~(_MALI_OSK_CPU_PAGE_SIZE - 1)) >> _MALI_OSK_CPU_PAGE_ORDER;
|
||
|
MALI_DEBUG_PRINT(6, ("Allocating page array of size %d bytes\n", allocation->num_pages * sizeof(struct page*)));
|
||
|
|
||
|
while (left > 0 && ((info->num_pages_allocated + pages_allocated) < info->num_pages_max) && _mali_osk_mem_check_allocated(os_mem_max_usage))
|
||
|
{
|
||
|
err = mali_allocation_engine_map_physical(engine, descriptor, *offset, MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC, info->cpu_usage_adjust, _MALI_OSK_CPU_PAGE_SIZE);
|
||
|
if ( _MALI_OSK_ERR_OK != err)
|
||
|
{
|
||
|
if ( _MALI_OSK_ERR_NOMEM == err)
|
||
|
{
|
||
|
/* 'Partial' allocation (or, out-of-memory on first page) */
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
MALI_DEBUG_PRINT(1, ("Mapping of physical memory failed\n"));
|
||
|
|
||
|
/* Fatal error, cleanup any previous pages allocated. */
|
||
|
if ( pages_allocated > 0 )
|
||
|
{
|
||
|
mali_allocation_engine_unmap_physical( engine, descriptor, allocation->offset_start, _MALI_OSK_CPU_PAGE_SIZE*pages_allocated, _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR );
|
||
|
/* (*offset) doesn't need to be restored; it will not be used by the caller on failure */
|
||
|
}
|
||
|
|
||
|
pages_allocated = 0;
|
||
|
|
||
|
result = MALI_MEM_ALLOC_INTERNAL_FAILURE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Loop iteration */
|
||
|
if (left < _MALI_OSK_CPU_PAGE_SIZE) left = 0;
|
||
|
else left -= _MALI_OSK_CPU_PAGE_SIZE;
|
||
|
|
||
|
pages_allocated++;
|
||
|
|
||
|
*offset += _MALI_OSK_CPU_PAGE_SIZE;
|
||
|
}
|
||
|
|
||
|
/* Loop termination; decide on result */
|
||
|
if (pages_allocated)
|
||
|
{
|
||
|
MALI_DEBUG_PRINT(6, ("Allocated %d pages\n", pages_allocated));
|
||
|
if (left) result = MALI_MEM_ALLOC_PARTIAL;
|
||
|
else result = MALI_MEM_ALLOC_FINISHED;
|
||
|
|
||
|
/* Some OS do not perform a full cache flush (including all outer caches) for uncached mapped memory.
|
||
|
* They zero the memory through a cached mapping, then flush the inner caches but not the outer caches.
|
||
|
* This is required for MALI to have the correct view of the memory.
|
||
|
*/
|
||
|
_mali_osk_cache_ensure_uncached_range_flushed( (void *)descriptor, allocation->offset_start, pages_allocated *_MALI_OSK_CPU_PAGE_SIZE );
|
||
|
allocation->num_pages = pages_allocated;
|
||
|
allocation->engine = engine; /* Necessary to make the engine's unmap call */
|
||
|
allocation->descriptor = descriptor; /* Necessary to make the engine's unmap call */
|
||
|
info->num_pages_allocated += pages_allocated;
|
||
|
|
||
|
MALI_DEBUG_PRINT(6, ("%d out of %d pages now allocated\n", info->num_pages_allocated, info->num_pages_max));
|
||
|
|
||
|
alloc_info->ctx = info;
|
||
|
alloc_info->handle = allocation;
|
||
|
alloc_info->release = os_allocator_release;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MALI_DEBUG_PRINT(6, ("Releasing pages array due to no pages allocated\n"));
|
||
|
_mali_osk_free( allocation );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static void os_allocator_release(void * ctx, void * handle)
|
||
|
{
|
||
|
os_allocator * info;
|
||
|
os_allocation * allocation;
|
||
|
mali_allocation_engine * engine;
|
||
|
mali_memory_allocation * descriptor;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER(ctx);
|
||
|
MALI_DEBUG_ASSERT_POINTER(handle);
|
||
|
|
||
|
info = (os_allocator*)ctx;
|
||
|
allocation = (os_allocation*)handle;
|
||
|
engine = allocation->engine;
|
||
|
descriptor = allocation->descriptor;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER( engine );
|
||
|
MALI_DEBUG_ASSERT_POINTER( descriptor );
|
||
|
|
||
|
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW))
|
||
|
{
|
||
|
MALI_DEBUG_PRINT(1, ("allocator release: Failed to get mutex\n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
MALI_DEBUG_PRINT(6, ("Releasing %d os pages\n", allocation->num_pages));
|
||
|
|
||
|
MALI_DEBUG_ASSERT( allocation->num_pages <= info->num_pages_allocated);
|
||
|
info->num_pages_allocated -= allocation->num_pages;
|
||
|
|
||
|
mali_allocation_engine_unmap_physical( engine, descriptor, allocation->offset_start, _MALI_OSK_CPU_PAGE_SIZE*allocation->num_pages, _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR );
|
||
|
|
||
|
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
|
||
|
|
||
|
_mali_osk_free(allocation);
|
||
|
}
|
||
|
|
||
|
static mali_physical_memory_allocation_result os_allocator_allocate_page_table_block(void * ctx, mali_page_table_block * block)
|
||
|
{
|
||
|
const int allocation_order = 6; /* _MALI_OSK_CPU_PAGE_SIZE << 6 */
|
||
|
void *virt;
|
||
|
const u32 pages_to_allocate = 1 << allocation_order;
|
||
|
const u32 size = _MALI_OSK_CPU_PAGE_SIZE << allocation_order;
|
||
|
os_allocator * info;
|
||
|
|
||
|
u32 cpu_phys_base;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER(ctx);
|
||
|
info = (os_allocator*)ctx;
|
||
|
|
||
|
/* Ensure we don't allocate more than we're supposed to from the ctx */
|
||
|
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW)) return MALI_MEM_ALLOC_INTERNAL_FAILURE;
|
||
|
|
||
|
if ( (info->num_pages_allocated + pages_to_allocate > info->num_pages_max) && _mali_osk_mem_check_allocated(info->num_pages_max * _MALI_OSK_CPU_PAGE_SIZE) )
|
||
|
{
|
||
|
/* return OOM */
|
||
|
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
|
||
|
return MALI_MEM_ALLOC_NONE;
|
||
|
}
|
||
|
|
||
|
virt = _mali_osk_mem_allocioregion( &cpu_phys_base, size );
|
||
|
|
||
|
if ( NULL == virt )
|
||
|
{
|
||
|
/* return OOM */
|
||
|
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
|
||
|
return MALI_MEM_ALLOC_NONE;
|
||
|
}
|
||
|
|
||
|
block->release = os_allocator_page_table_block_release;
|
||
|
block->ctx = ctx;
|
||
|
block->handle = (void*)allocation_order;
|
||
|
block->size = size;
|
||
|
block->phys_base = cpu_phys_base - info->cpu_usage_adjust;
|
||
|
block->mapping = virt;
|
||
|
|
||
|
info->num_pages_allocated += pages_to_allocate;
|
||
|
|
||
|
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
|
||
|
|
||
|
return MALI_MEM_ALLOC_FINISHED;
|
||
|
}
|
||
|
|
||
|
static void os_allocator_page_table_block_release( mali_page_table_block *page_table_block )
|
||
|
{
|
||
|
os_allocator * info;
|
||
|
u32 allocation_order;
|
||
|
u32 pages_allocated;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER( page_table_block );
|
||
|
|
||
|
info = (os_allocator*)page_table_block->ctx;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER( info );
|
||
|
|
||
|
allocation_order = (u32)page_table_block->handle;
|
||
|
|
||
|
pages_allocated = 1 << allocation_order;
|
||
|
|
||
|
MALI_DEBUG_ASSERT( pages_allocated * _MALI_OSK_CPU_PAGE_SIZE == page_table_block->size );
|
||
|
|
||
|
if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW))
|
||
|
{
|
||
|
MALI_DEBUG_PRINT(1, ("allocator release: Failed to get mutex\n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
MALI_DEBUG_ASSERT( pages_allocated <= info->num_pages_allocated);
|
||
|
info->num_pages_allocated -= pages_allocated;
|
||
|
|
||
|
/* Adjust phys_base from mali physical address to CPU physical address */
|
||
|
_mali_osk_mem_freeioregion( page_table_block->phys_base + info->cpu_usage_adjust, page_table_block->size, page_table_block->mapping );
|
||
|
|
||
|
_mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
|
||
|
}
|