349 lines
13 KiB
C
349 lines
13 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"
|
||
|
#include "mali_osk_list.h"
|
||
|
|
||
|
typedef struct memory_engine
|
||
|
{
|
||
|
mali_kernel_mem_address_manager * mali_address;
|
||
|
mali_kernel_mem_address_manager * process_address;
|
||
|
} memory_engine;
|
||
|
|
||
|
mali_allocation_engine mali_allocation_engine_create(mali_kernel_mem_address_manager * mali_address_manager, mali_kernel_mem_address_manager * process_address_manager)
|
||
|
{
|
||
|
memory_engine * engine;
|
||
|
|
||
|
/* Mali Address Manager need not support unmap_physical */
|
||
|
MALI_DEBUG_ASSERT_POINTER(mali_address_manager);
|
||
|
MALI_DEBUG_ASSERT_POINTER(mali_address_manager->allocate);
|
||
|
MALI_DEBUG_ASSERT_POINTER(mali_address_manager->release);
|
||
|
MALI_DEBUG_ASSERT_POINTER(mali_address_manager->map_physical);
|
||
|
|
||
|
/* Process Address Manager must support unmap_physical for OS allocation
|
||
|
* error path handling */
|
||
|
MALI_DEBUG_ASSERT_POINTER(process_address_manager);
|
||
|
MALI_DEBUG_ASSERT_POINTER(process_address_manager->allocate);
|
||
|
MALI_DEBUG_ASSERT_POINTER(process_address_manager->release);
|
||
|
MALI_DEBUG_ASSERT_POINTER(process_address_manager->map_physical);
|
||
|
MALI_DEBUG_ASSERT_POINTER(process_address_manager->unmap_physical);
|
||
|
|
||
|
|
||
|
engine = (memory_engine*)_mali_osk_malloc(sizeof(memory_engine));
|
||
|
if (NULL == engine) return NULL;
|
||
|
|
||
|
engine->mali_address = mali_address_manager;
|
||
|
engine->process_address = process_address_manager;
|
||
|
|
||
|
return (mali_allocation_engine)engine;
|
||
|
}
|
||
|
|
||
|
void mali_allocation_engine_destroy(mali_allocation_engine engine)
|
||
|
{
|
||
|
MALI_DEBUG_ASSERT_POINTER(engine);
|
||
|
_mali_osk_free(engine);
|
||
|
}
|
||
|
|
||
|
_mali_osk_errcode_t mali_allocation_engine_allocate_memory(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor, mali_physical_memory_allocator * physical_allocators, _mali_osk_list_t *tracking_list )
|
||
|
{
|
||
|
memory_engine * engine = (memory_engine*)mem_engine;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER(engine);
|
||
|
MALI_DEBUG_ASSERT_POINTER(descriptor);
|
||
|
MALI_DEBUG_ASSERT_POINTER(physical_allocators);
|
||
|
/* ASSERT that the list member has been initialized, even if it won't be
|
||
|
* used for tracking. We need it to be initialized to see if we need to
|
||
|
* delete it from a list in the release function. */
|
||
|
MALI_DEBUG_ASSERT( NULL != descriptor->list.next && NULL != descriptor->list.prev );
|
||
|
|
||
|
if (_MALI_OSK_ERR_OK == engine->mali_address->allocate(descriptor))
|
||
|
{
|
||
|
_mali_osk_errcode_t res = _MALI_OSK_ERR_OK;
|
||
|
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
|
||
|
{
|
||
|
res = engine->process_address->allocate(descriptor);
|
||
|
}
|
||
|
if ( _MALI_OSK_ERR_OK == res )
|
||
|
{
|
||
|
/* address space setup OK, commit physical memory to the allocation */
|
||
|
mali_physical_memory_allocator * active_allocator = physical_allocators;
|
||
|
struct mali_physical_memory_allocation * active_allocation_tracker = &descriptor->physical_allocation;
|
||
|
u32 offset = 0;
|
||
|
|
||
|
while ( NULL != active_allocator )
|
||
|
{
|
||
|
switch (active_allocator->allocate(active_allocator->ctx, mem_engine, descriptor, &offset, active_allocation_tracker))
|
||
|
{
|
||
|
case MALI_MEM_ALLOC_FINISHED:
|
||
|
if ( NULL != tracking_list )
|
||
|
{
|
||
|
/* Insert into the memory session list */
|
||
|
/* ASSERT that it is not already part of a list */
|
||
|
MALI_DEBUG_ASSERT( _mali_osk_list_empty( &descriptor->list ) );
|
||
|
_mali_osk_list_add( &descriptor->list, tracking_list );
|
||
|
}
|
||
|
|
||
|
MALI_SUCCESS; /* all done */
|
||
|
case MALI_MEM_ALLOC_NONE:
|
||
|
/* reuse current active_allocation_tracker */
|
||
|
MALI_DEBUG_PRINT( 4, ("Memory Engine Allocate: No allocation on %s, resorting to %s\n",
|
||
|
( active_allocator->name ) ? active_allocator->name : "UNNAMED",
|
||
|
( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") );
|
||
|
active_allocator = active_allocator->next;
|
||
|
break;
|
||
|
case MALI_MEM_ALLOC_PARTIAL:
|
||
|
if (NULL != active_allocator->next)
|
||
|
{
|
||
|
/* need a new allocation tracker */
|
||
|
active_allocation_tracker->next = _mali_osk_calloc(1, sizeof(mali_physical_memory_allocation));
|
||
|
if (NULL != active_allocation_tracker->next)
|
||
|
{
|
||
|
active_allocation_tracker = active_allocation_tracker->next;
|
||
|
MALI_DEBUG_PRINT( 2, ("Memory Engine Allocate: Partial allocation on %s, resorting to %s\n",
|
||
|
( active_allocator->name ) ? active_allocator->name : "UNNAMED",
|
||
|
( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") );
|
||
|
active_allocator = active_allocator->next;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
/* FALL THROUGH */
|
||
|
case MALI_MEM_ALLOC_INTERNAL_FAILURE:
|
||
|
active_allocator = NULL; /* end the while loop */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MALI_DEBUG_PRINT(3, ("Non-fatal OOM, have to cleanup, stopped at offset %d for size %d\n", offset, descriptor->size));
|
||
|
|
||
|
/* allocation failure, start cleanup */
|
||
|
/* loop over any potential partial allocations */
|
||
|
active_allocation_tracker = &descriptor->physical_allocation;
|
||
|
while (NULL != active_allocation_tracker)
|
||
|
{
|
||
|
/* handle blank trackers which will show up during failure */
|
||
|
if (NULL != active_allocation_tracker->release)
|
||
|
{
|
||
|
active_allocation_tracker->release(active_allocation_tracker->ctx, active_allocation_tracker->handle);
|
||
|
}
|
||
|
active_allocation_tracker = active_allocation_tracker->next;
|
||
|
}
|
||
|
|
||
|
/* free the allocation tracker objects themselves, skipping the tracker stored inside the descriptor itself */
|
||
|
for ( active_allocation_tracker = descriptor->physical_allocation.next; active_allocation_tracker != NULL; )
|
||
|
{
|
||
|
void * buf = active_allocation_tracker;
|
||
|
active_allocation_tracker = active_allocation_tracker->next;
|
||
|
_mali_osk_free(buf);
|
||
|
}
|
||
|
|
||
|
/* release the address spaces */
|
||
|
|
||
|
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
|
||
|
{
|
||
|
engine->process_address->release(descriptor);
|
||
|
}
|
||
|
}
|
||
|
engine->mali_address->release(descriptor);
|
||
|
}
|
||
|
|
||
|
MALI_ERROR(_MALI_OSK_ERR_FAULT);
|
||
|
}
|
||
|
|
||
|
void mali_allocation_engine_release_memory(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor)
|
||
|
{
|
||
|
memory_engine * engine = (memory_engine*)mem_engine;
|
||
|
mali_physical_memory_allocation * active_allocation_tracker;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER(engine);
|
||
|
MALI_DEBUG_ASSERT_POINTER(descriptor);
|
||
|
|
||
|
/* Determine whether we need to remove this from a tracking list */
|
||
|
if ( ! _mali_osk_list_empty( &descriptor->list ) )
|
||
|
{
|
||
|
_mali_osk_list_del( &descriptor->list );
|
||
|
/* Clear the list for debug mode, catch use-after-free */
|
||
|
MALI_DEBUG_CODE( descriptor->list.next = descriptor->list.prev = NULL; )
|
||
|
}
|
||
|
|
||
|
engine->mali_address->release(descriptor);
|
||
|
|
||
|
active_allocation_tracker = &descriptor->physical_allocation;
|
||
|
while (NULL != active_allocation_tracker)
|
||
|
{
|
||
|
MALI_DEBUG_ASSERT_POINTER(active_allocation_tracker->release);
|
||
|
active_allocation_tracker->release(active_allocation_tracker->ctx, active_allocation_tracker->handle);
|
||
|
active_allocation_tracker = active_allocation_tracker->next;
|
||
|
}
|
||
|
|
||
|
/* free the allocation tracker objects themselves, skipping the tracker stored inside the descriptor itself */
|
||
|
for ( active_allocation_tracker = descriptor->physical_allocation.next; active_allocation_tracker != NULL; )
|
||
|
{
|
||
|
void * buf = active_allocation_tracker;
|
||
|
active_allocation_tracker = active_allocation_tracker->next;
|
||
|
_mali_osk_free(buf);
|
||
|
}
|
||
|
|
||
|
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
|
||
|
{
|
||
|
engine->process_address->release(descriptor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
_mali_osk_errcode_t mali_allocation_engine_map_physical(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor, u32 offset, u32 phys, u32 cpu_usage_adjust, u32 size)
|
||
|
{
|
||
|
_mali_osk_errcode_t err;
|
||
|
memory_engine * engine = (memory_engine*)mem_engine;
|
||
|
_mali_osk_mem_mapregion_flags_t unmap_flags = (_mali_osk_mem_mapregion_flags_t)0;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER(engine);
|
||
|
MALI_DEBUG_ASSERT_POINTER(descriptor);
|
||
|
|
||
|
MALI_DEBUG_PRINT(7, ("Mapping phys 0x%08X length 0x%08X at offset 0x%08X\n", phys, size, offset));
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER(engine->mali_address);
|
||
|
MALI_DEBUG_ASSERT_POINTER(engine->mali_address->map_physical);
|
||
|
|
||
|
/* Handle process address manager first, because we may need them to
|
||
|
* allocate the physical page */
|
||
|
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
|
||
|
{
|
||
|
/* Handle OS-allocated specially, since an adjustment may be required */
|
||
|
if ( MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC == phys )
|
||
|
{
|
||
|
MALI_DEBUG_ASSERT( _MALI_OSK_CPU_PAGE_SIZE == size );
|
||
|
|
||
|
/* Set flags to use on error path */
|
||
|
unmap_flags |= _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR;
|
||
|
|
||
|
err = engine->process_address->map_physical(descriptor, offset, &phys, size);
|
||
|
/* Adjust for cpu physical address to mali physical address */
|
||
|
phys -= cpu_usage_adjust;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
u32 cpu_phys;
|
||
|
/* Adjust mali physical address to cpu physical address */
|
||
|
cpu_phys = phys + cpu_usage_adjust;
|
||
|
err = engine->process_address->map_physical(descriptor, offset, &cpu_phys, size);
|
||
|
}
|
||
|
|
||
|
if ( _MALI_OSK_ERR_OK != err )
|
||
|
{
|
||
|
MALI_ERROR( err );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MALI_DEBUG_PRINT(4, ("Mapping phys 0x%08X length 0x%08X at offset 0x%08X to CPUVA 0x%08X\n", phys, size, offset, (u32)(descriptor->mapping) + offset));
|
||
|
|
||
|
/* Mali address manager must use the physical address - no point in asking
|
||
|
* it to allocate another one for us */
|
||
|
MALI_DEBUG_ASSERT( MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC != phys );
|
||
|
|
||
|
err = engine->mali_address->map_physical(descriptor, offset, &phys, size);
|
||
|
|
||
|
if ( _MALI_OSK_ERR_OK != err )
|
||
|
{
|
||
|
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
|
||
|
{
|
||
|
MALI_DEBUG_PRINT( 2, ("Process address manager succeeded, but Mali Address manager failed for phys=0x%08X size=0x%08X, offset=0x%08X. Will unmap.\n", phys, size, offset));
|
||
|
engine->process_address->unmap_physical(descriptor, offset, size, unmap_flags);
|
||
|
}
|
||
|
|
||
|
MALI_ERROR( err );
|
||
|
}
|
||
|
|
||
|
MALI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
void mali_allocation_engine_unmap_physical(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor, u32 offset, u32 size, _mali_osk_mem_mapregion_flags_t unmap_flags )
|
||
|
{
|
||
|
memory_engine * engine = (memory_engine*)mem_engine;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER(engine);
|
||
|
MALI_DEBUG_ASSERT_POINTER(descriptor);
|
||
|
|
||
|
MALI_DEBUG_PRINT(7, ("UnMapping length 0x%08X at offset 0x%08X\n", size, offset));
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER(engine->mali_address);
|
||
|
MALI_DEBUG_ASSERT_POINTER(engine->process_address);
|
||
|
|
||
|
if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
|
||
|
{
|
||
|
/* Mandetory for process_address manager to have an unmap function*/
|
||
|
engine->process_address->unmap_physical( descriptor, offset, size, unmap_flags );
|
||
|
}
|
||
|
|
||
|
/* Optional for mali_address manager to have an unmap function*/
|
||
|
if ( NULL != engine->mali_address->unmap_physical )
|
||
|
{
|
||
|
engine->mali_address->unmap_physical( descriptor, offset, size, unmap_flags );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
_mali_osk_errcode_t mali_allocation_engine_allocate_page_tables(mali_allocation_engine engine, mali_page_table_block * descriptor, mali_physical_memory_allocator * physical_provider)
|
||
|
{
|
||
|
mali_physical_memory_allocator * active_allocator = physical_provider;
|
||
|
|
||
|
MALI_DEBUG_ASSERT_POINTER(descriptor);
|
||
|
MALI_DEBUG_ASSERT_POINTER(physical_provider);
|
||
|
|
||
|
while ( NULL != active_allocator )
|
||
|
{
|
||
|
switch (active_allocator->allocate_page_table_block(active_allocator->ctx, descriptor))
|
||
|
{
|
||
|
case MALI_MEM_ALLOC_FINISHED:
|
||
|
MALI_SUCCESS; /* all done */
|
||
|
case MALI_MEM_ALLOC_NONE:
|
||
|
/* try next */
|
||
|
MALI_DEBUG_PRINT( 2, ("Memory Engine Allocate PageTables: No allocation on %s, resorting to %s\n",
|
||
|
( active_allocator->name ) ? active_allocator->name : "UNNAMED",
|
||
|
( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") );
|
||
|
active_allocator = active_allocator->next;
|
||
|
break;
|
||
|
case MALI_MEM_ALLOC_PARTIAL:
|
||
|
MALI_DEBUG_PRINT(1, ("Invalid return value from allocate_page_table_block call: MALI_MEM_ALLOC_PARTIAL\n"));
|
||
|
/* FALL THROUGH */
|
||
|
case MALI_MEM_ALLOC_INTERNAL_FAILURE:
|
||
|
MALI_DEBUG_PRINT(1, ("Aborting due to allocation failure\n"));
|
||
|
active_allocator = NULL; /* end the while loop */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MALI_ERROR(_MALI_OSK_ERR_FAULT);
|
||
|
}
|
||
|
|
||
|
|
||
|
void mali_allocation_engine_report_allocators( mali_physical_memory_allocator * physical_provider )
|
||
|
{
|
||
|
mali_physical_memory_allocator * active_allocator = physical_provider;
|
||
|
MALI_DEBUG_ASSERT_POINTER(physical_provider);
|
||
|
|
||
|
MALI_DEBUG_PRINT( 1, ("Mali memory allocators will be used in this order of preference (lowest numbered first) :\n"));
|
||
|
while ( NULL != active_allocator )
|
||
|
{
|
||
|
if ( NULL != active_allocator->name )
|
||
|
{
|
||
|
MALI_DEBUG_PRINT( 1, ("\t%d: %s\n", active_allocator->alloc_order, active_allocator->name) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MALI_DEBUG_PRINT( 1, ("\t%d: (UNNAMED ALLOCATOR)\n", active_allocator->alloc_order) );
|
||
|
}
|
||
|
active_allocator = active_allocator->next;
|
||
|
}
|
||
|
|
||
|
}
|