2 * Copyright (C) 2011-2012 ARM Limited. All rights reserved.
4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
7 * A copy of the licence is included with the program, and can also be obtained from Free Software
8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
11 #include "mali_kernel_common.h"
12 #include "mali_kernel_memory_engine.h"
14 #include "mali_osk_list.h"
16 typedef struct memory_engine
18 mali_kernel_mem_address_manager * mali_address;
19 mali_kernel_mem_address_manager * process_address;
22 mali_allocation_engine mali_allocation_engine_create(mali_kernel_mem_address_manager * mali_address_manager, mali_kernel_mem_address_manager * process_address_manager)
24 memory_engine * engine;
26 /* Mali Address Manager need not support unmap_physical */
27 MALI_DEBUG_ASSERT_POINTER(mali_address_manager);
28 MALI_DEBUG_ASSERT_POINTER(mali_address_manager->allocate);
29 MALI_DEBUG_ASSERT_POINTER(mali_address_manager->release);
30 MALI_DEBUG_ASSERT_POINTER(mali_address_manager->map_physical);
32 /* Process Address Manager must support unmap_physical for OS allocation
33 * error path handling */
34 MALI_DEBUG_ASSERT_POINTER(process_address_manager);
35 MALI_DEBUG_ASSERT_POINTER(process_address_manager->allocate);
36 MALI_DEBUG_ASSERT_POINTER(process_address_manager->release);
37 MALI_DEBUG_ASSERT_POINTER(process_address_manager->map_physical);
38 MALI_DEBUG_ASSERT_POINTER(process_address_manager->unmap_physical);
41 engine = (memory_engine*)_mali_osk_malloc(sizeof(memory_engine));
42 if (NULL == engine) return NULL;
44 engine->mali_address = mali_address_manager;
45 engine->process_address = process_address_manager;
47 return (mali_allocation_engine)engine;
50 void mali_allocation_engine_destroy(mali_allocation_engine engine)
52 MALI_DEBUG_ASSERT_POINTER(engine);
53 _mali_osk_free(engine);
56 _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 )
58 memory_engine * engine = (memory_engine*)mem_engine;
60 MALI_DEBUG_ASSERT_POINTER(engine);
61 MALI_DEBUG_ASSERT_POINTER(descriptor);
62 MALI_DEBUG_ASSERT_POINTER(physical_allocators);
63 /* ASSERT that the list member has been initialized, even if it won't be
64 * used for tracking. We need it to be initialized to see if we need to
65 * delete it from a list in the release function. */
66 MALI_DEBUG_ASSERT( NULL != descriptor->list.next && NULL != descriptor->list.prev );
68 if (_MALI_OSK_ERR_OK == engine->mali_address->allocate(descriptor))
70 _mali_osk_errcode_t res = _MALI_OSK_ERR_OK;
71 if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
73 res = engine->process_address->allocate(descriptor);
75 if ( _MALI_OSK_ERR_OK == res )
77 /* address space setup OK, commit physical memory to the allocation */
78 mali_physical_memory_allocator * active_allocator = physical_allocators;
79 struct mali_physical_memory_allocation * active_allocation_tracker = &descriptor->physical_allocation;
82 while ( NULL != active_allocator )
84 switch (active_allocator->allocate(active_allocator->ctx, mem_engine, descriptor, &offset, active_allocation_tracker))
86 case MALI_MEM_ALLOC_FINISHED:
87 if ( NULL != tracking_list )
89 /* Insert into the memory session list */
90 /* ASSERT that it is not already part of a list */
91 MALI_DEBUG_ASSERT( _mali_osk_list_empty( &descriptor->list ) );
92 _mali_osk_list_add( &descriptor->list, tracking_list );
95 MALI_SUCCESS; /* all done */
96 case MALI_MEM_ALLOC_NONE:
97 /* reuse current active_allocation_tracker */
98 MALI_DEBUG_PRINT( 4, ("Memory Engine Allocate: No allocation on %s, resorting to %s\n",
99 ( active_allocator->name ) ? active_allocator->name : "UNNAMED",
100 ( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") );
101 active_allocator = active_allocator->next;
103 case MALI_MEM_ALLOC_PARTIAL:
104 if (NULL != active_allocator->next)
106 /* need a new allocation tracker */
107 active_allocation_tracker->next = _mali_osk_calloc(1, sizeof(mali_physical_memory_allocation));
108 if (NULL != active_allocation_tracker->next)
110 active_allocation_tracker = active_allocation_tracker->next;
111 MALI_DEBUG_PRINT( 2, ("Memory Engine Allocate: Partial allocation on %s, resorting to %s\n",
112 ( active_allocator->name ) ? active_allocator->name : "UNNAMED",
113 ( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") );
114 active_allocator = active_allocator->next;
119 case MALI_MEM_ALLOC_INTERNAL_FAILURE:
120 active_allocator = NULL; /* end the while loop */
125 MALI_PRINT(("Memory allocate failed, could not allocate size %d kB.\n", descriptor->size/1024));
127 /* allocation failure, start cleanup */
128 /* loop over any potential partial allocations */
129 active_allocation_tracker = &descriptor->physical_allocation;
130 while (NULL != active_allocation_tracker)
132 /* handle blank trackers which will show up during failure */
133 if (NULL != active_allocation_tracker->release)
135 active_allocation_tracker->release(active_allocation_tracker->ctx, active_allocation_tracker->handle);
137 active_allocation_tracker = active_allocation_tracker->next;
140 /* free the allocation tracker objects themselves, skipping the tracker stored inside the descriptor itself */
141 for ( active_allocation_tracker = descriptor->physical_allocation.next; active_allocation_tracker != NULL; )
143 void * buf = active_allocation_tracker;
144 active_allocation_tracker = active_allocation_tracker->next;
148 /* release the address spaces */
150 if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
152 engine->process_address->release(descriptor);
155 engine->mali_address->release(descriptor);
158 MALI_ERROR(_MALI_OSK_ERR_FAULT);
161 void mali_allocation_engine_release_memory(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor)
163 mali_allocation_engine_release_pt1_mali_pagetables_unmap(mem_engine, descriptor);
164 mali_allocation_engine_release_pt2_physical_memory_free(mem_engine, descriptor);
167 void mali_allocation_engine_release_pt1_mali_pagetables_unmap(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor)
169 memory_engine * engine = (memory_engine*)mem_engine;
171 MALI_DEBUG_ASSERT_POINTER(engine);
172 MALI_DEBUG_ASSERT_POINTER(descriptor);
174 /* Calling: mali_address_manager_release() */
175 /* This function is allowed to be called several times, and it only does the release on the first call. */
176 engine->mali_address->release(descriptor);
179 void mali_allocation_engine_release_pt2_physical_memory_free(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor)
181 memory_engine * engine = (memory_engine*)mem_engine;
182 mali_physical_memory_allocation * active_allocation_tracker;
184 /* Remove this from a tracking list in session_data->memory_head */
185 if ( ! _mali_osk_list_empty( &descriptor->list ) )
187 _mali_osk_list_del( &descriptor->list );
188 /* Clear the list for debug mode, catch use-after-free */
189 MALI_DEBUG_CODE( descriptor->list.next = descriptor->list.prev = NULL; )
192 active_allocation_tracker = &descriptor->physical_allocation;
193 while (NULL != active_allocation_tracker)
195 MALI_DEBUG_ASSERT_POINTER(active_allocation_tracker->release);
196 active_allocation_tracker->release(active_allocation_tracker->ctx, active_allocation_tracker->handle);
197 active_allocation_tracker = active_allocation_tracker->next;
200 /* free the allocation tracker objects themselves, skipping the tracker stored inside the descriptor itself */
201 for ( active_allocation_tracker = descriptor->physical_allocation.next; active_allocation_tracker != NULL; )
203 void * buf = active_allocation_tracker;
204 active_allocation_tracker = active_allocation_tracker->next;
208 if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
210 engine->process_address->release(descriptor);
214 _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)
216 _mali_osk_errcode_t err;
217 memory_engine * engine = (memory_engine*)mem_engine;
218 _mali_osk_mem_mapregion_flags_t unmap_flags = (_mali_osk_mem_mapregion_flags_t)0;
220 MALI_DEBUG_ASSERT_POINTER(engine);
221 MALI_DEBUG_ASSERT_POINTER(descriptor);
223 MALI_DEBUG_PRINT(7, ("Mapping phys 0x%08X length 0x%08X at offset 0x%08X\n", phys, size, offset));
225 MALI_DEBUG_ASSERT_POINTER(engine->mali_address);
226 MALI_DEBUG_ASSERT_POINTER(engine->mali_address->map_physical);
228 /* Handle process address manager first, because we may need them to
229 * allocate the physical page */
230 if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
232 /* Handle OS-allocated specially, since an adjustment may be required */
233 if ( MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC == phys )
235 MALI_DEBUG_ASSERT( _MALI_OSK_CPU_PAGE_SIZE == size );
237 /* Set flags to use on error path */
238 unmap_flags |= _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR;
240 err = engine->process_address->map_physical(descriptor, offset, &phys, size);
241 /* Adjust for cpu physical address to mali physical address */
242 phys -= cpu_usage_adjust;
247 /* Adjust mali physical address to cpu physical address */
248 cpu_phys = phys + cpu_usage_adjust;
249 err = engine->process_address->map_physical(descriptor, offset, &cpu_phys, size);
252 if ( _MALI_OSK_ERR_OK != err )
254 MALI_DEBUG_PRINT(2, ("Map failed: %s %d\n", __FUNCTION__, __LINE__));
259 MALI_DEBUG_PRINT(7, ("Mapping phys 0x%08X length 0x%08X at offset 0x%08X to CPUVA 0x%08X\n", phys, size, offset, (u32)(descriptor->mapping) + offset));
261 /* Mali address manager must use the physical address - no point in asking
262 * it to allocate another one for us */
263 MALI_DEBUG_ASSERT( MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC != phys );
265 err = engine->mali_address->map_physical(descriptor, offset, &phys, size);
267 if ( _MALI_OSK_ERR_OK != err )
269 if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
271 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));
272 engine->process_address->unmap_physical(descriptor, offset, size, unmap_flags);
274 MALI_DEBUG_PRINT(2, ("Map mali failed: %s %d\n", __FUNCTION__, __LINE__));
281 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 )
283 memory_engine * engine = (memory_engine*)mem_engine;
285 MALI_DEBUG_ASSERT_POINTER(engine);
286 MALI_DEBUG_ASSERT_POINTER(descriptor);
288 MALI_DEBUG_PRINT(7, ("UnMapping length 0x%08X at offset 0x%08X\n", size, offset));
290 MALI_DEBUG_ASSERT_POINTER(engine->mali_address);
291 MALI_DEBUG_ASSERT_POINTER(engine->process_address);
293 if ( descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE )
295 /* Mandetory for process_address manager to have an unmap function*/
296 engine->process_address->unmap_physical( descriptor, offset, size, unmap_flags );
299 /* Optional for mali_address manager to have an unmap function*/
300 if ( NULL != engine->mali_address->unmap_physical )
302 engine->mali_address->unmap_physical( descriptor, offset, size, unmap_flags );
307 _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)
309 mali_physical_memory_allocator * active_allocator = physical_provider;
311 MALI_DEBUG_ASSERT_POINTER(descriptor);
312 MALI_DEBUG_ASSERT_POINTER(physical_provider);
314 while ( NULL != active_allocator )
316 switch (active_allocator->allocate_page_table_block(active_allocator->ctx, descriptor))
318 case MALI_MEM_ALLOC_FINISHED:
319 MALI_SUCCESS; /* all done */
320 case MALI_MEM_ALLOC_NONE:
322 MALI_DEBUG_PRINT( 2, ("Memory Engine Allocate PageTables: No allocation on %s, resorting to %s\n",
323 ( active_allocator->name ) ? active_allocator->name : "UNNAMED",
324 ( active_allocator->next ) ? (( active_allocator->next->name )? active_allocator->next->name : "UNNAMED") : "NONE") );
325 active_allocator = active_allocator->next;
327 case MALI_MEM_ALLOC_PARTIAL:
328 MALI_DEBUG_PRINT(1, ("Invalid return value from allocate_page_table_block call: MALI_MEM_ALLOC_PARTIAL\n"));
330 case MALI_MEM_ALLOC_INTERNAL_FAILURE:
331 MALI_DEBUG_PRINT(1, ("Aborting due to allocation failure\n"));
332 active_allocator = NULL; /* end the while loop */
337 MALI_ERROR(_MALI_OSK_ERR_FAULT);
341 void mali_allocation_engine_report_allocators( mali_physical_memory_allocator * physical_provider )
343 mali_physical_memory_allocator * active_allocator = physical_provider;
344 MALI_DEBUG_ASSERT_POINTER(physical_provider);
346 MALI_DEBUG_PRINT( 1, ("Mali memory allocators will be used in this order of preference (lowest numbered first) :\n"));
347 while ( NULL != active_allocator )
349 if ( NULL != active_allocator->name )
351 MALI_DEBUG_PRINT( 1, ("\t%d: %s\n", active_allocator->alloc_order, active_allocator->name) );
355 MALI_DEBUG_PRINT( 1, ("\t%d: (UNNAMED ALLOCATOR)\n", active_allocator->alloc_order) );
357 active_allocator = active_allocator->next;
362 u32 mali_allocation_engine_memory_usage(mali_physical_memory_allocator *allocator)
365 while(NULL != allocator)
367 /* Only count allocators that have set up a stat function. */
369 sum += allocator->stat(allocator);
371 allocator = allocator->next;