tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / mali / common / mali_memory.c
1 /*
2  * Copyright (C) 2011-2012 ARM Limited. All rights reserved.
3  *
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.
6  *
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.
9  */
10
11 #include "mali_kernel_common.h"
12 #include "mali_kernel_descriptor_mapping.h"
13 #include "mali_mem_validation.h"
14 #include "mali_memory.h"
15 #include "mali_mmu_page_directory.h"
16 #include "mali_kernel_memory_engine.h"
17 #include "mali_block_allocator.h"
18 #include "mali_kernel_mem_os.h"
19 #include "mali_session.h"
20 #include "mali_l2_cache.h"
21 #include "mali_scheduler.h"
22 #if defined(CONFIG_MALI400_UMP)
23 #include "ump_kernel_interface.h"
24 #endif
25
26 /* kernel side OS functions and user-kernel interface */
27 #include "mali_osk.h"
28 #include "mali_osk_mali.h"
29 #include "mali_ukk.h"
30 #include "mali_osk_list.h"
31 #include "mali_osk_bitops.h"
32
33 /**
34  * Per-session memory descriptor mapping table sizes
35  */
36 #define MALI_MEM_DESCRIPTORS_INIT 64
37 #define MALI_MEM_DESCRIPTORS_MAX 65536
38
39 typedef struct dedicated_memory_info
40 {
41         u32 base;
42         u32 size;
43         struct dedicated_memory_info * next;
44 } dedicated_memory_info;
45
46 /* types used for external_memory and ump_memory physical memory allocators, which are using the mali_allocation_engine */
47 #if defined(CONFIG_MALI400_UMP)
48 typedef struct ump_mem_allocation
49 {
50         mali_allocation_engine * engine;
51         mali_memory_allocation * descriptor;
52         u32 initial_offset;
53         u32 size_allocated;
54         ump_dd_handle ump_mem;
55 } ump_mem_allocation ;
56 #endif
57
58 typedef struct external_mem_allocation
59 {
60         mali_allocation_engine * engine;
61         mali_memory_allocation * descriptor;
62         u32 initial_offset;
63         u32 size;
64 } external_mem_allocation;
65
66 /**
67  * @brief Internal function for unmapping memory
68  *
69  * Worker function for unmapping memory from a user-process. We assume that the
70  * session/descriptor's lock was obtained before entry. For example, the
71  * wrapper _mali_ukk_mem_munmap() will lock the descriptor, then call this
72  * function to do the actual unmapping. mali_memory_core_session_end() could
73  * also call this directly (depending on compilation options), having locked
74  * the descriptor.
75  *
76  * This function will fail if it is unable to put the MMU in stall mode (which
77  * might be the case if a page fault is also being processed).
78  *
79  * @param args see _mali_uk_mem_munmap_s in "mali_utgard_uk_types.h"
80  * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure.
81  */
82 static _mali_osk_errcode_t _mali_ukk_mem_munmap_internal( _mali_uk_mem_munmap_s *args );
83
84 #if defined(CONFIG_MALI400_UMP)
85 static void ump_memory_release(void * ctx, void * handle);
86 static mali_physical_memory_allocation_result ump_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info);
87 #endif /* CONFIG_MALI400_UMP */
88
89
90 static void external_memory_release(void * ctx, void * handle);
91 static mali_physical_memory_allocation_result external_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info);
92
93
94 /* nop functions */
95
96 /* mali address manager needs to allocate page tables on allocate, write to page table(s) on map, write to page table(s) and release page tables on release */
97 static _mali_osk_errcode_t  mali_address_manager_allocate(mali_memory_allocation * descriptor); /* validates the range, allocates memory for the page tables if needed */
98 static _mali_osk_errcode_t  mali_address_manager_map(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size);
99 static void mali_address_manager_release(mali_memory_allocation * descriptor);
100
101 /* MMU variables */
102
103 typedef struct mali_mmu_page_table_allocation
104 {
105         _mali_osk_list_t list;
106         u32 * usage_map;
107         u32 usage_count;
108         u32 num_pages;
109         mali_page_table_block pages;
110 } mali_mmu_page_table_allocation;
111
112 typedef struct mali_mmu_page_table_allocations
113 {
114         _mali_osk_lock_t *lock;
115         _mali_osk_list_t partial;
116         _mali_osk_list_t full;
117         /* we never hold on to a empty allocation */
118 } mali_mmu_page_table_allocations;
119
120 static mali_kernel_mem_address_manager mali_address_manager =
121 {
122         mali_address_manager_allocate, /* allocate */
123         mali_address_manager_release,  /* release */
124         mali_address_manager_map,      /* map_physical */
125         NULL                           /* unmap_physical not present*/
126 };
127
128 /* the mmu page table cache */
129 static struct mali_mmu_page_table_allocations page_table_cache;
130
131
132 static mali_kernel_mem_address_manager process_address_manager =
133 {
134         _mali_osk_mem_mapregion_init,  /* allocate */
135         _mali_osk_mem_mapregion_term,  /* release */
136         _mali_osk_mem_mapregion_map,   /* map_physical */
137         _mali_osk_mem_mapregion_unmap  /* unmap_physical */
138 };
139
140 static _mali_osk_errcode_t mali_mmu_page_table_cache_create(void);
141 static void mali_mmu_page_table_cache_destroy(void);
142
143 static mali_allocation_engine memory_engine = NULL;
144 static mali_physical_memory_allocator * physical_memory_allocators = NULL;
145
146 static dedicated_memory_info * mem_region_registrations = NULL;
147
148 mali_allocation_engine mali_mem_get_memory_engine(void)
149 {
150         return memory_engine;
151 }
152
153 /* called during module init */
154 _mali_osk_errcode_t mali_memory_initialize(void)
155 {
156         _mali_osk_errcode_t err;
157
158         MALI_DEBUG_PRINT(2, ("Memory system initializing\n"));
159
160         err = mali_mmu_page_table_cache_create();
161         if(_MALI_OSK_ERR_OK != err)
162         {
163                 MALI_ERROR(err);
164         }
165
166         memory_engine = mali_allocation_engine_create(&mali_address_manager, &process_address_manager);
167         MALI_CHECK_NON_NULL( memory_engine, _MALI_OSK_ERR_FAULT);
168
169         MALI_SUCCESS;
170 }
171
172 /* called if/when our module is unloaded */
173 void mali_memory_terminate(void)
174 {
175         MALI_DEBUG_PRINT(2, ("Memory system terminating\n"));
176
177         mali_mmu_page_table_cache_destroy();
178
179         while ( NULL != mem_region_registrations)
180         {
181                 dedicated_memory_info * m;
182                 m = mem_region_registrations;
183                 mem_region_registrations = m->next;
184                 _mali_osk_mem_unreqregion(m->base, m->size);
185                 _mali_osk_free(m);
186         }
187
188         while ( NULL != physical_memory_allocators)
189         {
190                 mali_physical_memory_allocator * m;
191                 m = physical_memory_allocators;
192                 physical_memory_allocators = m->next;
193                 m->destroy(m);
194         }
195
196         if (NULL != memory_engine)
197         {
198                 mali_allocation_engine_destroy(memory_engine);
199                 memory_engine = NULL;
200         }
201 }
202
203 _mali_osk_errcode_t mali_memory_session_begin(struct mali_session_data * session_data)
204 {
205         MALI_DEBUG_PRINT(5, ("Memory session begin\n"));
206
207         /* create descriptor mapping table */
208         session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX);
209
210         if (NULL == session_data->descriptor_mapping)
211         {
212                 MALI_ERROR(_MALI_OSK_ERR_NOMEM);
213         }
214
215         session_data->memory_lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK
216                                         | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_MEM_SESSION);
217         if (NULL == session_data->memory_lock)
218         {
219                 mali_descriptor_mapping_destroy(session_data->descriptor_mapping);
220                 _mali_osk_free(session_data);
221                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
222         }
223
224         /* Init the session's memory allocation list */
225         _MALI_OSK_INIT_LIST_HEAD( &session_data->memory_head );
226
227         MALI_DEBUG_PRINT(5, ("MMU session begin: success\n"));
228         MALI_SUCCESS;
229 }
230
231 static void descriptor_table_cleanup_callback(int descriptor_id, void* map_target)
232 {
233         mali_memory_allocation * descriptor;
234
235         descriptor = (mali_memory_allocation*)map_target;
236
237         MALI_DEBUG_PRINT(3, ("Cleanup of descriptor %d mapping to 0x%x in descriptor table\n", descriptor_id, map_target));
238         MALI_DEBUG_ASSERT(descriptor);
239
240         mali_allocation_engine_release_memory(memory_engine, descriptor);
241         _mali_osk_free(descriptor);
242 }
243
244 void mali_memory_session_end(struct mali_session_data *session_data)
245 {
246         _mali_osk_errcode_t err = _MALI_OSK_ERR_BUSY;
247
248         MALI_DEBUG_PRINT(3, ("MMU session end\n"));
249
250         if (NULL == session_data)
251         {
252                 MALI_DEBUG_PRINT(1, ("No session data found during session end\n"));
253                 return;
254         }
255
256         while (err == _MALI_OSK_ERR_BUSY)
257         {
258                 /* Lock the session so we can modify the memory list */
259                 _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW );
260                 err = _MALI_OSK_ERR_OK;
261
262                 /* Free all memory engine allocations */
263                 if (!_mali_osk_list_empty(&session_data->memory_head))
264                 {
265                         mali_memory_allocation *descriptor;
266                         mali_memory_allocation *temp;
267                         _mali_uk_mem_munmap_s unmap_args;
268
269                         MALI_DEBUG_PRINT(1, ("Memory found on session usage list during session termination\n"));
270
271                         unmap_args.ctx = session_data;
272
273                         /* use the 'safe' list iterator, since freeing removes the active block from the list we're iterating */
274                         _MALI_OSK_LIST_FOREACHENTRY(descriptor, temp, &session_data->memory_head, mali_memory_allocation, list)
275                         {
276                                 MALI_DEBUG_PRINT(4, ("Freeing block with mali address 0x%x size %d mapped in user space at 0x%x\n",
277                                                         descriptor->mali_address, descriptor->size, descriptor->size, descriptor->mapping)
278                                                 );
279                                 /* ASSERT that the descriptor's lock references the correct thing */
280                                 MALI_DEBUG_ASSERT(  descriptor->lock == session_data->memory_lock );
281                                 /* Therefore, we have already locked the descriptor */
282
283                                 unmap_args.size = descriptor->size;
284                                 unmap_args.mapping = descriptor->mapping;
285                                 unmap_args.cookie = (u32)descriptor;
286
287                                 /*
288                                         * This removes the descriptor from the list, and frees the descriptor
289                                         *
290                                         * Does not handle the _MALI_OSK_SPECIFIC_INDIRECT_MMAP case, since
291                                         * the only OS we are aware of that requires indirect MMAP also has
292                                         * implicit mmap cleanup.
293                                         */
294                                 err = _mali_ukk_mem_munmap_internal( &unmap_args );
295
296                                 if (err == _MALI_OSK_ERR_BUSY)
297                                 {
298                                         _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW );
299                                         /*
300                                                 * Reason for this;
301                                                 * We where unable to stall the MMU, probably because we are in page fault handling.
302                                                 * Sleep for a while with the session lock released, then try again.
303                                                 * Abnormal termination of programs with running Mali jobs is a normal reason for this.
304                                                 */
305                                         _mali_osk_time_ubusydelay(10);
306                                         break; /* Will jump back into: "while (err == _MALI_OSK_ERR_BUSY)" */
307                                 }
308                         }
309                 }
310         }
311         /* Assert that we really did free everything */
312         MALI_DEBUG_ASSERT( _mali_osk_list_empty(&session_data->memory_head) );
313
314         if (NULL != session_data->descriptor_mapping)
315         {
316                 mali_descriptor_mapping_call_for_each(session_data->descriptor_mapping, descriptor_table_cleanup_callback);
317                 mali_descriptor_mapping_destroy(session_data->descriptor_mapping);
318                 session_data->descriptor_mapping = NULL;
319         }
320
321         _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW );
322
323         /**
324          * @note Could the VMA close handler mean that we use the session data after it was freed?
325          * In which case, would need to refcount the session data, and free on VMA close
326          */
327
328         /* Free the lock */
329         _mali_osk_lock_term( session_data->memory_lock );
330
331         return;
332 }
333
334 _mali_osk_errcode_t mali_memory_core_resource_os_memory(u32 size)
335 {
336         mali_physical_memory_allocator * allocator;
337         mali_physical_memory_allocator ** next_allocator_list;
338
339         u32 alloc_order = 1; /* OS memory has second priority */
340
341         allocator = mali_os_allocator_create(size, 0 /* cpu_usage_adjust */, "Shared Mali GPU memory");
342         if (NULL == allocator)
343         {
344                 MALI_DEBUG_PRINT(1, ("Failed to create OS memory allocator\n"));
345                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
346         }
347
348         allocator->alloc_order = alloc_order;
349
350         /* link in the allocator: insertion into ordered list
351          * resources of the same alloc_order will be Last-in-first */
352         next_allocator_list = &physical_memory_allocators;
353
354         while (NULL != *next_allocator_list &&
355                         (*next_allocator_list)->alloc_order < alloc_order )
356         {
357                 next_allocator_list = &((*next_allocator_list)->next);
358         }
359
360         allocator->next = (*next_allocator_list);
361         (*next_allocator_list) = allocator;
362
363         MALI_SUCCESS;
364 }
365
366 _mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(u32 start, u32 size)
367 {
368         mali_physical_memory_allocator * allocator;
369         mali_physical_memory_allocator ** next_allocator_list;
370         dedicated_memory_info * cleanup_data;
371
372         u32 alloc_order = 0; /* Dedicated range has first priority */
373
374         /* do the low level linux operation first */
375
376         /* Request ownership of the memory */
377         if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(start, size, "Dedicated Mali GPU memory"))
378         {
379                 MALI_DEBUG_PRINT(1, ("Failed to request memory region for frame buffer (0x%08X - 0x%08X)\n", start, start + size - 1));
380                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
381         }
382
383         /* create generic block allocator object to handle it */
384         allocator = mali_block_allocator_create(start, 0 /* cpu_usage_adjust */, size, "Dedicated Mali GPU memory");
385
386         if (NULL == allocator)
387         {
388                 MALI_DEBUG_PRINT(1, ("Memory bank registration failed\n"));
389                 _mali_osk_mem_unreqregion(start, size);
390                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
391         }
392
393         /* save low level cleanup info */
394         allocator->alloc_order = alloc_order;
395
396         cleanup_data = _mali_osk_malloc(sizeof(dedicated_memory_info));
397
398         if (NULL == cleanup_data)
399         {
400                 _mali_osk_mem_unreqregion(start, size);
401                 allocator->destroy(allocator);
402                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
403         }
404
405         cleanup_data->base = start;
406         cleanup_data->size = size;
407
408         cleanup_data->next = mem_region_registrations;
409         mem_region_registrations = cleanup_data;
410
411         /* link in the allocator: insertion into ordered list
412          * resources of the same alloc_order will be Last-in-first */
413         next_allocator_list = &physical_memory_allocators;
414
415         while ( NULL != *next_allocator_list &&
416                         (*next_allocator_list)->alloc_order < alloc_order )
417         {
418                 next_allocator_list = &((*next_allocator_list)->next);
419         }
420
421         allocator->next = (*next_allocator_list);
422         (*next_allocator_list) = allocator;
423
424         MALI_SUCCESS;
425 }
426
427 #if defined(CONFIG_MALI400_UMP)
428 static mali_physical_memory_allocation_result ump_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info)
429 {
430         ump_dd_handle ump_mem;
431         u32 nr_blocks;
432         u32 i;
433         ump_dd_physical_block * ump_blocks;
434         ump_mem_allocation *ret_allocation;
435
436         MALI_DEBUG_ASSERT_POINTER(ctx);
437         MALI_DEBUG_ASSERT_POINTER(engine);
438         MALI_DEBUG_ASSERT_POINTER(descriptor);
439         MALI_DEBUG_ASSERT_POINTER(alloc_info);
440
441         ret_allocation = _mali_osk_malloc( sizeof( ump_mem_allocation ) );
442         if ( NULL==ret_allocation ) return MALI_MEM_ALLOC_INTERNAL_FAILURE;
443
444         ump_mem = (ump_dd_handle)ctx;
445
446         MALI_DEBUG_PRINT(4, ("In ump_memory_commit\n"));
447
448         nr_blocks = ump_dd_phys_block_count_get(ump_mem);
449
450         MALI_DEBUG_PRINT(4, ("Have %d blocks\n", nr_blocks));
451
452         if (nr_blocks == 0)
453         {
454                 MALI_DEBUG_PRINT(1, ("No block count\n"));
455                 _mali_osk_free( ret_allocation );
456                 return MALI_MEM_ALLOC_INTERNAL_FAILURE;
457         }
458
459         ump_blocks = _mali_osk_malloc(sizeof(*ump_blocks)*nr_blocks );
460         if ( NULL==ump_blocks )
461         {
462                 _mali_osk_free( ret_allocation );
463                 return MALI_MEM_ALLOC_INTERNAL_FAILURE;
464         }
465
466         if (UMP_DD_INVALID == ump_dd_phys_blocks_get(ump_mem, ump_blocks, nr_blocks))
467         {
468                 _mali_osk_free(ump_blocks);
469                 _mali_osk_free( ret_allocation );
470                 return MALI_MEM_ALLOC_INTERNAL_FAILURE;
471         }
472
473         /* Store away the initial offset for unmapping purposes */
474         ret_allocation->initial_offset = *offset;
475
476         for(i=0; i<nr_blocks; ++i)
477         {
478                 MALI_DEBUG_PRINT(4, ("Mapping in 0x%08x size %d\n", ump_blocks[i].addr , ump_blocks[i].size));
479                 if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, ump_blocks[i].addr , 0, ump_blocks[i].size ))
480                 {
481                         u32 size_allocated = *offset - ret_allocation->initial_offset;
482                         MALI_DEBUG_PRINT(1, ("Mapping of external memory failed\n"));
483
484                         /* unmap all previous blocks (if any) */
485                         mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 );
486
487                         _mali_osk_free(ump_blocks);
488                         _mali_osk_free(ret_allocation);
489                         return MALI_MEM_ALLOC_INTERNAL_FAILURE;
490                 }
491                 *offset += ump_blocks[i].size;
492         }
493
494         if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE)
495         {
496                 /* Map in an extra virtual guard page at the end of the VMA */
497                 MALI_DEBUG_PRINT(4, ("Mapping in extra guard page\n"));
498                 if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, ump_blocks[0].addr , 0, _MALI_OSK_MALI_PAGE_SIZE ))
499                 {
500                         u32 size_allocated = *offset - ret_allocation->initial_offset;
501                         MALI_DEBUG_PRINT(1, ("Mapping of external memory (guard page) failed\n"));
502
503                         /* unmap all previous blocks (if any) */
504                         mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 );
505
506                         _mali_osk_free(ump_blocks);
507                         _mali_osk_free(ret_allocation);
508                         return MALI_MEM_ALLOC_INTERNAL_FAILURE;
509                 }
510                 *offset += _MALI_OSK_MALI_PAGE_SIZE;
511         }
512
513         _mali_osk_free( ump_blocks );
514
515         ret_allocation->engine = engine;
516         ret_allocation->descriptor = descriptor;
517         ret_allocation->ump_mem = ump_mem;
518         ret_allocation->size_allocated = *offset - ret_allocation->initial_offset;
519
520         alloc_info->ctx = NULL;
521         alloc_info->handle = ret_allocation;
522         alloc_info->next = NULL;
523         alloc_info->release = ump_memory_release;
524
525         return MALI_MEM_ALLOC_FINISHED;
526 }
527
528 static void ump_memory_release(void * ctx, void * handle)
529 {
530         ump_dd_handle ump_mem;
531         ump_mem_allocation *allocation;
532
533         allocation = (ump_mem_allocation *)handle;
534
535         MALI_DEBUG_ASSERT_POINTER( allocation );
536
537         ump_mem = allocation->ump_mem;
538
539         MALI_DEBUG_ASSERT(UMP_DD_HANDLE_INVALID!=ump_mem);
540
541         /* At present, this is a no-op. But, it allows the mali_address_manager to
542          * do unmapping of a subrange in future. */
543         mali_allocation_engine_unmap_physical( allocation->engine,
544                                                                                    allocation->descriptor,
545                                                                                    allocation->initial_offset,
546                                                                                    allocation->size_allocated,
547                                                                                    (_mali_osk_mem_mapregion_flags_t)0
548                                                                                    );
549         _mali_osk_free( allocation );
550
551
552         ump_dd_reference_release(ump_mem) ;
553         return;
554 }
555
556 _mali_osk_errcode_t _mali_ukk_attach_ump_mem( _mali_uk_attach_ump_mem_s *args )
557 {
558         ump_dd_handle ump_mem;
559         mali_physical_memory_allocator external_memory_allocator;
560         struct mali_session_data *session_data;
561         mali_memory_allocation * descriptor;
562         int md;
563
564         MALI_DEBUG_ASSERT_POINTER(args);
565         MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
566
567         session_data = (struct mali_session_data *)args->ctx;
568         MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS);
569
570         /* check arguments */
571         /* NULL might be a valid Mali address */
572         if ( ! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS);
573
574         /* size must be a multiple of the system page size */
575         if ( args->size % _MALI_OSK_MALI_PAGE_SIZE ) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS);
576
577         MALI_DEBUG_PRINT(3,
578                          ("Requested to map ump memory with secure id %d into virtual memory 0x%08X, size 0x%08X\n",
579                           args->secure_id, args->mali_address, args->size));
580
581         ump_mem = ump_dd_handle_create_from_secure_id( (int)args->secure_id ) ;
582
583         if ( UMP_DD_HANDLE_INVALID==ump_mem ) MALI_ERROR(_MALI_OSK_ERR_FAULT);
584
585         descriptor = _mali_osk_calloc(1, sizeof(mali_memory_allocation));
586         if (NULL == descriptor)
587         {
588                 ump_dd_reference_release(ump_mem);
589                 MALI_ERROR(_MALI_OSK_ERR_NOMEM);
590         }
591
592         descriptor->size = args->size;
593         descriptor->mapping = NULL;
594         descriptor->mali_address = args->mali_address;
595         descriptor->mali_addr_mapping_info = (void*)session_data;
596         descriptor->process_addr_mapping_info = NULL; /* do not map to process address space */
597         descriptor->cache_settings = (u32) MALI_CACHE_STANDARD;
598         descriptor->lock = session_data->memory_lock;
599
600         if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE)
601         {
602                 descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE;
603         }
604         _mali_osk_list_init( &descriptor->list );
605
606         if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, descriptor, &md))
607         {
608                 ump_dd_reference_release(ump_mem);
609                 _mali_osk_free(descriptor);
610                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
611         }
612
613         external_memory_allocator.allocate = ump_memory_commit;
614         external_memory_allocator.allocate_page_table_block = NULL;
615         external_memory_allocator.ctx = ump_mem;
616         external_memory_allocator.name = "UMP Memory";
617         external_memory_allocator.next = NULL;
618
619         _mali_osk_lock_wait(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW);
620
621         if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_memory(memory_engine, descriptor, &external_memory_allocator, NULL))
622         {
623                 _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW);
624                 mali_descriptor_mapping_free(session_data->descriptor_mapping, md);
625                 ump_dd_reference_release(ump_mem);
626                 _mali_osk_free(descriptor);
627                 MALI_ERROR(_MALI_OSK_ERR_NOMEM);
628         }
629
630         _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW);
631
632         args->cookie = md;
633
634         MALI_DEBUG_PRINT(5,("Returning from UMP attach\n"));
635
636         /* All OK */
637         MALI_SUCCESS;
638 }
639
640
641 _mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args )
642 {
643         mali_memory_allocation * descriptor;
644         struct mali_session_data *session_data;
645
646         MALI_DEBUG_ASSERT_POINTER(args);
647         MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
648
649         session_data = (struct mali_session_data *)args->ctx;
650         MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS);
651
652         if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session_data->descriptor_mapping, args->cookie, (void**)&descriptor))
653         {
654                 MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to release ump memory\n", args->cookie));
655                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
656         }
657
658         descriptor = mali_descriptor_mapping_free(session_data->descriptor_mapping, args->cookie);
659
660         if (NULL != descriptor)
661         {
662                 _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW );
663
664                 mali_allocation_engine_release_memory(memory_engine, descriptor);
665
666                 _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW );
667
668                 _mali_osk_free(descriptor);
669         }
670
671         MALI_SUCCESS;
672
673 }
674 #endif /* CONFIG_MALI400_UMP */
675
676
677 static mali_physical_memory_allocation_result external_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info)
678 {
679         u32 * data;
680         external_mem_allocation * ret_allocation;
681
682         MALI_DEBUG_ASSERT_POINTER(ctx);
683         MALI_DEBUG_ASSERT_POINTER(engine);
684         MALI_DEBUG_ASSERT_POINTER(descriptor);
685         MALI_DEBUG_ASSERT_POINTER(alloc_info);
686
687         ret_allocation = _mali_osk_malloc( sizeof(external_mem_allocation) );
688
689         if ( NULL == ret_allocation )
690         {
691                 return MALI_MEM_ALLOC_INTERNAL_FAILURE;
692         }
693
694         data = (u32*)ctx;
695
696         ret_allocation->engine = engine;
697         ret_allocation->descriptor = descriptor;
698         ret_allocation->initial_offset = *offset;
699
700         alloc_info->ctx = NULL;
701         alloc_info->handle = ret_allocation;
702         alloc_info->next = NULL;
703         alloc_info->release = external_memory_release;
704
705         MALI_DEBUG_PRINT(5, ("External map: mapping phys 0x%08X at mali virtual address 0x%08X staring at offset 0x%08X length 0x%08X\n", data[0], descriptor->mali_address, *offset, data[1]));
706
707         if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, data[0], 0, data[1]))
708         {
709                 MALI_DEBUG_PRINT(1, ("Mapping of external memory failed\n"));
710                 _mali_osk_free(ret_allocation);
711                 return MALI_MEM_ALLOC_INTERNAL_FAILURE;
712         }
713         *offset += data[1];
714
715         if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE)
716         {
717                 /* Map in an extra virtual guard page at the end of the VMA */
718                 MALI_DEBUG_PRINT(4, ("Mapping in extra guard page\n"));
719                 if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, data[0], 0, _MALI_OSK_MALI_PAGE_SIZE))
720                 {
721                         u32 size_allocated = *offset - ret_allocation->initial_offset;
722                         MALI_DEBUG_PRINT(1, ("Mapping of external memory (guard page) failed\n"));
723
724                         /* unmap what we previously mapped */
725                         mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 );
726                         _mali_osk_free(ret_allocation);
727                         return MALI_MEM_ALLOC_INTERNAL_FAILURE;
728                 }
729                 *offset += _MALI_OSK_MALI_PAGE_SIZE;
730         }
731
732         ret_allocation->size = *offset - ret_allocation->initial_offset;
733
734         return MALI_MEM_ALLOC_FINISHED;
735 }
736
737 static void external_memory_release(void * ctx, void * handle)
738 {
739         external_mem_allocation * allocation;
740
741         allocation = (external_mem_allocation *) handle;
742         MALI_DEBUG_ASSERT_POINTER( allocation );
743
744         /* At present, this is a no-op. But, it allows the mali_address_manager to
745          * do unmapping of a subrange in future. */
746
747         mali_allocation_engine_unmap_physical( allocation->engine,
748                                                                                    allocation->descriptor,
749                                                                                    allocation->initial_offset,
750                                                                                    allocation->size,
751                                                                                    (_mali_osk_mem_mapregion_flags_t)0
752                                                                                    );
753
754         _mali_osk_free( allocation );
755
756         return;
757 }
758
759 _mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args )
760 {
761         mali_physical_memory_allocator external_memory_allocator;
762         struct mali_session_data *session_data;
763         u32 info[2];
764         mali_memory_allocation * descriptor;
765         int md;
766
767         MALI_DEBUG_ASSERT_POINTER(args);
768         MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
769
770         session_data = (struct mali_session_data *)args->ctx;
771         MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS);
772
773         external_memory_allocator.allocate = external_memory_commit;
774         external_memory_allocator.allocate_page_table_block = NULL;
775         external_memory_allocator.ctx = &info[0];
776         external_memory_allocator.name = "External Memory";
777         external_memory_allocator.next = NULL;
778
779         /* check arguments */
780         /* NULL might be a valid Mali address */
781         if ( ! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS);
782
783         /* size must be a multiple of the system page size */
784         if ( args->size % _MALI_OSK_MALI_PAGE_SIZE ) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS);
785
786         MALI_DEBUG_PRINT(3,
787                 ("Requested to map physical memory 0x%x-0x%x into virtual memory 0x%x\n",
788                 (void*)args->phys_addr,
789                 (void*)(args->phys_addr + args->size -1),
790                 (void*)args->mali_address)
791         );
792
793         /* Validate the mali physical range */
794         if (_MALI_OSK_ERR_OK != mali_mem_validation_check(args->phys_addr, args->size))
795         {
796                 return _MALI_OSK_ERR_FAULT;
797         }
798
799         info[0] = args->phys_addr;
800         info[1] = args->size;
801
802         descriptor = _mali_osk_calloc(1, sizeof(mali_memory_allocation));
803         if (NULL == descriptor) MALI_ERROR(_MALI_OSK_ERR_NOMEM);
804
805         descriptor->size = args->size;
806         descriptor->mapping = NULL;
807         descriptor->mali_address = args->mali_address;
808         descriptor->mali_addr_mapping_info = (void*)session_data;
809         descriptor->process_addr_mapping_info = NULL; /* do not map to process address space */
810         descriptor->cache_settings = (u32)MALI_CACHE_STANDARD;
811         descriptor->lock = session_data->memory_lock;
812         if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE)
813         {
814                 descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE;
815         }
816         _mali_osk_list_init( &descriptor->list );
817
818         _mali_osk_lock_wait(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW);
819
820         if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_memory(memory_engine, descriptor, &external_memory_allocator, NULL))
821         {
822                 _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW);
823                 _mali_osk_free(descriptor);
824                 MALI_ERROR(_MALI_OSK_ERR_NOMEM);
825         }
826
827         _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW);
828
829         if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, descriptor, &md))
830         {
831                 mali_allocation_engine_release_memory(memory_engine, descriptor);
832                 _mali_osk_free(descriptor);
833                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
834         }
835
836         args->cookie = md;
837
838         MALI_DEBUG_PRINT(5,("Returning from range_map_external_memory\n"));
839
840         /* All OK */
841         MALI_SUCCESS;
842 }
843
844
845 _mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args )
846 {
847         mali_memory_allocation * descriptor;
848         void* old_value;
849         struct mali_session_data *session_data;
850
851         MALI_DEBUG_ASSERT_POINTER(args);
852         MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
853
854         session_data = (struct mali_session_data *)args->ctx;
855         MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS);
856
857         if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session_data->descriptor_mapping, args->cookie, (void**)&descriptor))
858         {
859                 MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to unmap external memory\n", args->cookie));
860                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
861         }
862
863         old_value = mali_descriptor_mapping_free(session_data->descriptor_mapping, args->cookie);
864
865         if (NULL != old_value)
866         {
867                 _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW );
868
869                 mali_allocation_engine_release_memory(memory_engine, descriptor);
870
871                 _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW );
872
873                 _mali_osk_free(descriptor);
874         }
875
876         MALI_SUCCESS;
877 }
878
879 _mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args )
880 {
881         MALI_DEBUG_ASSERT_POINTER(args);
882         MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
883
884         args->memory_size = 2 * 1024 * 1024 * 1024UL; /* 2GB address space */
885         args->mali_address_base = 1 * 1024 * 1024 * 1024UL; /* staring at 1GB, causing this layout: (0-1GB unused)(1GB-3G usage by Mali)(3G-4G unused) */
886         MALI_SUCCESS;
887 }
888
889 _mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args )
890 {
891         MALI_DEBUG_ASSERT_POINTER(args);
892         MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
893         MALI_SUCCESS;
894 }
895
896 static _mali_osk_errcode_t mali_address_manager_allocate(mali_memory_allocation * descriptor)
897 {
898         struct mali_session_data *session_data;
899         u32 actual_size;
900
901         MALI_DEBUG_ASSERT_POINTER(descriptor);
902
903         session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info;
904
905         actual_size = descriptor->size;
906
907         if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE)
908         {
909                 actual_size += _MALI_OSK_MALI_PAGE_SIZE;
910         }
911
912         return mali_mmu_pagedir_map(session_data->page_directory, descriptor->mali_address, actual_size);
913 }
914
915 static void mali_address_manager_release(mali_memory_allocation * descriptor)
916 {
917         const u32 illegal_mali_address = 0xffffffff;
918         struct mali_session_data *session_data;
919         MALI_DEBUG_ASSERT_POINTER(descriptor);
920
921         /* It is allowed to call this function several times on the same descriptor.
922            When memory is released we set the illegal_mali_address so we can early out here. */
923         if ( illegal_mali_address == descriptor->mali_address) return;
924
925         session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info;
926         mali_mmu_pagedir_unmap(session_data->page_directory, descriptor->mali_address, descriptor->size);
927
928         descriptor->mali_address = illegal_mali_address ;
929 }
930
931 static _mali_osk_errcode_t mali_address_manager_map(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size)
932 {
933         struct mali_session_data *session_data;
934         u32 mali_address;
935
936         MALI_DEBUG_ASSERT_POINTER(descriptor);
937         MALI_DEBUG_ASSERT_POINTER(phys_addr);
938
939         session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info;
940         MALI_DEBUG_ASSERT_POINTER(session_data);
941
942         mali_address = descriptor->mali_address + offset;
943
944         MALI_DEBUG_PRINT(7, ("Mali map: mapping 0x%08X to Mali address 0x%08X length 0x%08X\n", *phys_addr, mali_address, size));
945
946         mali_mmu_pagedir_update(session_data->page_directory, mali_address, *phys_addr, size, descriptor->cache_settings);
947
948         MALI_SUCCESS;
949 }
950
951 /* This handler registered to mali_mmap for MMU builds */
952 _mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args )
953 {
954         struct mali_session_data *session_data;
955         mali_memory_allocation * descriptor;
956
957         /* validate input */
958         if (NULL == args) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: args was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); }
959
960         /* Unpack arguments */
961         session_data = (struct mali_session_data *)args->ctx;
962
963         /* validate input */
964         if (NULL == session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_FAULT); }
965
966         descriptor = (mali_memory_allocation*) _mali_osk_calloc( 1, sizeof(mali_memory_allocation) );
967         if (NULL == descriptor) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: descriptor was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_NOMEM); }
968
969         descriptor->size = args->size;
970         descriptor->mali_address = args->phys_addr;
971         descriptor->mali_addr_mapping_info = (void*)session_data;
972
973         descriptor->process_addr_mapping_info = args->ukk_private; /* save to be used during physical manager callback */
974         descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE;
975         descriptor->cache_settings = (u32) args->cache_settings ;
976         descriptor->lock = session_data->memory_lock;
977         _mali_osk_list_init( &descriptor->list );
978
979         _mali_osk_lock_wait(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW);
980
981         if (0 == mali_allocation_engine_allocate_memory(memory_engine, descriptor, physical_memory_allocators, &session_data->memory_head))
982         {
983                 /* We do not FLUSH nor TLB_ZAP on MMAP, since we do both of those on job start*/
984                 _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW);
985
986                 args->mapping = descriptor->mapping;
987                 args->cookie = (u32)descriptor;
988
989                 MALI_DEBUG_PRINT(7, ("MMAP OK\n"));
990                 MALI_SUCCESS;
991         }
992         else
993         {
994                 _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW);
995                 /* OOM, but not a fatal error */
996                 MALI_DEBUG_PRINT(4, ("Memory allocation failure, OOM\n"));
997                 _mali_osk_free(descriptor);
998                 /* Linux will free the CPU address allocation, userspace client the Mali address allocation */
999                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
1000         }
1001 }
1002
1003 static _mali_osk_errcode_t _mali_ukk_mem_munmap_internal( _mali_uk_mem_munmap_s *args )
1004 {
1005         struct mali_session_data *session_data;
1006         mali_memory_allocation * descriptor;
1007
1008         descriptor = (mali_memory_allocation *)args->cookie;
1009         MALI_DEBUG_ASSERT_POINTER(descriptor);
1010
1011         /** @note args->context unused; we use the memory_session from the cookie */
1012         /* args->mapping and args->size are also discarded. They are only necessary
1013            for certain do_munmap implementations. However, they could be used to check the
1014            descriptor at this point. */
1015
1016         session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info;
1017         MALI_DEBUG_ASSERT_POINTER(session_data);
1018
1019         /* Unmapping the memory from the mali virtual address space.
1020            It is allowed to call this function severeal times, which might happen if zapping below fails. */
1021         mali_allocation_engine_release_pt1_mali_pagetables_unmap(memory_engine, descriptor);
1022
1023 #ifdef MALI_UNMAP_FLUSH_ALL_MALI_L2
1024         {
1025                 u32 i;
1026                 u32 number_of_l2_ccores = mali_l2_cache_core_get_glob_num_l2_cores();
1027                 for (i = 0; i < number_of_l2_ccores; i++)
1028                 {
1029                         struct mali_l2_cache_core *core;
1030                         core = mali_l2_cache_core_get_glob_l2_core(i);
1031                         if (mali_l2_cache_power_is_enabled_get(core) )
1032                         {
1033                                 mali_l2_cache_invalidate_all_force(core);
1034                         }
1035                 }
1036         }
1037 #endif
1038
1039         mali_scheduler_zap_all_active(session_data);
1040
1041         /* Removes the descriptor from the session's memory list, releases physical memory, releases descriptor */
1042         mali_allocation_engine_release_pt2_physical_memory_free(memory_engine, descriptor);
1043
1044         _mali_osk_free(descriptor);
1045
1046         return _MALI_OSK_ERR_OK;
1047 }
1048
1049 /* Handler for unmapping memory for MMU builds */
1050 _mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args )
1051 {
1052         mali_memory_allocation * descriptor;
1053         _mali_osk_lock_t *descriptor_lock;
1054         _mali_osk_errcode_t err;
1055
1056         descriptor = (mali_memory_allocation *)args->cookie;
1057         MALI_DEBUG_ASSERT_POINTER(descriptor);
1058
1059         /** @note args->context unused; we use the memory_session from the cookie */
1060         /* args->mapping and args->size are also discarded. They are only necessary
1061         for certain do_munmap implementations. However, they could be used to check the
1062         descriptor at this point. */
1063
1064         MALI_DEBUG_ASSERT_POINTER((struct mali_session_data *)descriptor->mali_addr_mapping_info);
1065
1066         descriptor_lock = descriptor->lock; /* should point to the session data lock... */
1067
1068         err = _MALI_OSK_ERR_BUSY;
1069         while (err == _MALI_OSK_ERR_BUSY)
1070         {
1071                 if (descriptor_lock)
1072                 {
1073                         _mali_osk_lock_wait( descriptor_lock, _MALI_OSK_LOCKMODE_RW );
1074                 }
1075
1076                 err = _mali_ukk_mem_munmap_internal( args );
1077
1078                 if (descriptor_lock)
1079                 {
1080                         _mali_osk_lock_signal( descriptor_lock, _MALI_OSK_LOCKMODE_RW );
1081                 }
1082
1083                 if (err == _MALI_OSK_ERR_BUSY)
1084                 {
1085                         /*
1086                          * Reason for this;
1087                          * We where unable to stall the MMU, probably because we are in page fault handling.
1088                          * Sleep for a while with the session lock released, then try again.
1089                          * Abnormal termination of programs with running Mali jobs is a normal reason for this.
1090                          */
1091                         _mali_osk_time_ubusydelay(10);
1092                 }
1093         }
1094
1095         return err;
1096 }
1097
1098 u32 _mali_ukk_report_memory_usage(void)
1099 {
1100         return mali_allocation_engine_memory_usage(physical_memory_allocators);
1101 }
1102
1103 _mali_osk_errcode_t mali_mmu_get_table_page(u32 *table_page, mali_io_address *mapping)
1104 {
1105         _mali_osk_lock_wait(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW);
1106
1107         if (!_mali_osk_list_empty(&page_table_cache.partial))
1108         {
1109                 mali_mmu_page_table_allocation * alloc = _MALI_OSK_LIST_ENTRY(page_table_cache.partial.next, mali_mmu_page_table_allocation, list);
1110                 int page_number = _mali_osk_find_first_zero_bit(alloc->usage_map, alloc->num_pages);
1111                 MALI_DEBUG_PRINT(6, ("Partial page table allocation found, using page offset %d\n", page_number));
1112                 _mali_osk_set_nonatomic_bit(page_number, alloc->usage_map);
1113                 alloc->usage_count++;
1114                 if (alloc->num_pages == alloc->usage_count)
1115                 {
1116                         /* full, move alloc to full list*/
1117                         _mali_osk_list_move(&alloc->list, &page_table_cache.full);
1118                 }
1119                 _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW);
1120
1121                 *table_page = (MALI_MMU_PAGE_SIZE * page_number) + alloc->pages.phys_base;
1122                 *mapping =  (mali_io_address)((MALI_MMU_PAGE_SIZE * page_number) + (u32)alloc->pages.mapping);
1123                 MALI_DEBUG_PRINT(4, ("Page table allocated for VA=0x%08X, MaliPA=0x%08X\n", *mapping, *table_page ));
1124                 MALI_SUCCESS;
1125         }
1126         else
1127         {
1128                 mali_mmu_page_table_allocation * alloc;
1129                 /* no free pages, allocate a new one */
1130
1131                 alloc = (mali_mmu_page_table_allocation *)_mali_osk_calloc(1, sizeof(mali_mmu_page_table_allocation));
1132                 if (NULL == alloc)
1133                 {
1134                         _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW);
1135                         *table_page = MALI_INVALID_PAGE;
1136                         MALI_ERROR(_MALI_OSK_ERR_NOMEM);
1137                 }
1138
1139                 _MALI_OSK_INIT_LIST_HEAD(&alloc->list);
1140
1141                 if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_page_tables(memory_engine, &alloc->pages, physical_memory_allocators))
1142                 {
1143                         MALI_DEBUG_PRINT(1, ("No more memory for page tables\n"));
1144                         _mali_osk_free(alloc);
1145                         _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW);
1146                         *table_page = MALI_INVALID_PAGE;
1147                         *mapping = NULL;
1148                         MALI_ERROR(_MALI_OSK_ERR_NOMEM);
1149                 }
1150
1151                 /* create the usage map */
1152                 alloc->num_pages = alloc->pages.size / MALI_MMU_PAGE_SIZE;
1153                 alloc->usage_count = 1;
1154                 MALI_DEBUG_PRINT(3, ("New page table cache expansion, %d pages in new cache allocation\n", alloc->num_pages));
1155                 alloc->usage_map = _mali_osk_calloc(1, ((alloc->num_pages + BITS_PER_LONG - 1) & ~(BITS_PER_LONG-1) / BITS_PER_LONG) * sizeof(unsigned long));
1156                 if (NULL == alloc->usage_map)
1157                 {
1158                         MALI_DEBUG_PRINT(1, ("Failed to allocate memory to describe MMU page table cache usage\n"));
1159                         alloc->pages.release(&alloc->pages);
1160                         _mali_osk_free(alloc);
1161                         _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW);
1162                         *table_page = MALI_INVALID_PAGE;
1163                         *mapping = NULL;
1164                         MALI_ERROR(_MALI_OSK_ERR_NOMEM);
1165                 }
1166
1167                 _mali_osk_set_nonatomic_bit(0, alloc->usage_map);
1168
1169                 if (alloc->num_pages > 1)
1170                 {
1171                         _mali_osk_list_add(&alloc->list, &page_table_cache.partial);
1172                 }
1173                 else
1174                 {
1175                         _mali_osk_list_add(&alloc->list, &page_table_cache.full);
1176                 }
1177
1178                 _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW);
1179                 *table_page = alloc->pages.phys_base; /* return the first page */
1180                 *mapping = alloc->pages.mapping; /* Mapping for first page */
1181                 MALI_DEBUG_PRINT(4, ("Page table allocated: VA=0x%08X, MaliPA=0x%08X\n", *mapping, *table_page ));
1182                 MALI_SUCCESS;
1183         }
1184 }
1185
1186 void mali_mmu_release_table_page(u32 pa)
1187 {
1188         mali_mmu_page_table_allocation * alloc, * temp_alloc;
1189
1190         MALI_DEBUG_PRINT_IF(1, pa & 4095, ("Bad page address 0x%x given to mali_mmu_release_table_page\n", (void*)pa));
1191
1192         MALI_DEBUG_PRINT(4, ("Releasing table page 0x%08X to the cache\n", pa));
1193
1194         _mali_osk_lock_wait(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW);
1195
1196         /* find the entry this address belongs to */
1197         /* first check the partial list */
1198         _MALI_OSK_LIST_FOREACHENTRY(alloc, temp_alloc, &page_table_cache.partial, mali_mmu_page_table_allocation, list)
1199         {
1200                 u32 start = alloc->pages.phys_base;
1201                 u32 last = start + (alloc->num_pages - 1) * MALI_MMU_PAGE_SIZE;
1202                 if (pa >= start && pa <= last)
1203                 {
1204                         MALI_DEBUG_ASSERT(0 != _mali_osk_test_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map));
1205                         _mali_osk_clear_nonatomic_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map);
1206                         alloc->usage_count--;
1207
1208                         _mali_osk_memset((void*)( ((u32)alloc->pages.mapping) + (pa - start) ), 0, MALI_MMU_PAGE_SIZE);
1209
1210                         if (0 == alloc->usage_count)
1211                         {
1212                                 /* empty, release whole page alloc */
1213                                 _mali_osk_list_del(&alloc->list);
1214                                 alloc->pages.release(&alloc->pages);
1215                                 _mali_osk_free(alloc->usage_map);
1216                                 _mali_osk_free(alloc);
1217                         }
1218                         _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW);
1219                         MALI_DEBUG_PRINT(4, ("(partial list)Released table page 0x%08X to the cache\n", pa));
1220                         return;
1221                 }
1222         }
1223
1224         /* the check the full list */
1225         _MALI_OSK_LIST_FOREACHENTRY(alloc, temp_alloc, &page_table_cache.full, mali_mmu_page_table_allocation, list)
1226         {
1227                 u32 start = alloc->pages.phys_base;
1228                 u32 last = start + (alloc->num_pages - 1) * MALI_MMU_PAGE_SIZE;
1229                 if (pa >= start && pa <= last)
1230                 {
1231                         _mali_osk_clear_nonatomic_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map);
1232                         alloc->usage_count--;
1233
1234                         _mali_osk_memset((void*)( ((u32)alloc->pages.mapping) + (pa - start) ), 0, MALI_MMU_PAGE_SIZE);
1235
1236
1237                         if (0 == alloc->usage_count)
1238                         {
1239                                 /* empty, release whole page alloc */
1240                                 _mali_osk_list_del(&alloc->list);
1241                                 alloc->pages.release(&alloc->pages);
1242                                 _mali_osk_free(alloc->usage_map);
1243                                 _mali_osk_free(alloc);
1244                         }
1245                         else
1246                         {
1247                                 /* transfer to partial list */
1248                                 _mali_osk_list_move(&alloc->list, &page_table_cache.partial);
1249                         }
1250
1251                         _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW);
1252                         MALI_DEBUG_PRINT(4, ("(full list)Released table page 0x%08X to the cache\n", pa));
1253                         return;
1254                 }
1255         }
1256
1257         MALI_DEBUG_PRINT(1, ("pa 0x%x not found in the page table cache\n", (void*)pa));
1258
1259         _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW);
1260 }
1261
1262 static _mali_osk_errcode_t mali_mmu_page_table_cache_create(void)
1263 {
1264         page_table_cache.lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK
1265                                     | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_MEM_PT_CACHE);
1266         MALI_CHECK_NON_NULL( page_table_cache.lock, _MALI_OSK_ERR_FAULT );
1267         _MALI_OSK_INIT_LIST_HEAD(&page_table_cache.partial);
1268         _MALI_OSK_INIT_LIST_HEAD(&page_table_cache.full);
1269         MALI_SUCCESS;
1270 }
1271
1272 static void mali_mmu_page_table_cache_destroy(void)
1273 {
1274         mali_mmu_page_table_allocation * alloc, *temp;
1275
1276         _MALI_OSK_LIST_FOREACHENTRY(alloc, temp, &page_table_cache.partial, mali_mmu_page_table_allocation, list)
1277         {
1278                 MALI_DEBUG_PRINT_IF(1, 0 != alloc->usage_count, ("Destroying page table cache while pages are tagged as in use. %d allocations still marked as in use.\n", alloc->usage_count));
1279                 _mali_osk_list_del(&alloc->list);
1280                 alloc->pages.release(&alloc->pages);
1281                 _mali_osk_free(alloc->usage_map);
1282                 _mali_osk_free(alloc);
1283         }
1284
1285         MALI_DEBUG_PRINT_IF(1, !_mali_osk_list_empty(&page_table_cache.full), ("Page table cache full list contains one or more elements \n"));
1286
1287         _MALI_OSK_LIST_FOREACHENTRY(alloc, temp, &page_table_cache.full, mali_mmu_page_table_allocation, list)
1288         {
1289                 MALI_DEBUG_PRINT(1, ("Destroy alloc 0x%08X with usage count %d\n", (u32)alloc, alloc->usage_count));
1290                 _mali_osk_list_del(&alloc->list);
1291                 alloc->pages.release(&alloc->pages);
1292                 _mali_osk_free(alloc->usage_map);
1293                 _mali_osk_free(alloc);
1294         }
1295
1296         _mali_osk_lock_term(page_table_cache.lock);
1297 }