tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / gpu / arm / mali400 / r4p0_rel0 / linux / mali_memory.c
1 /*
2  * Copyright (C) 2013 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 <linux/list.h>
12 #include <linux/mm.h>
13 #include <linux/mm_types.h>
14 #include <linux/fs.h>
15 #include <linux/dma-mapping.h>
16 #include <linux/slab.h>
17 #include <linux/version.h>
18 #include <linux/platform_device.h>
19
20
21 #include "mali_osk.h"
22 #include "mali_osk_mali.h"
23 #include "mali_kernel_linux.h"
24 #include "mali_scheduler.h"
25 #include "mali_kernel_descriptor_mapping.h"
26 #include "mali_osk_bitops.h"
27
28 #include "mali_memory.h"
29 #include "mali_memory_dma_buf.h"
30 #include "mali_memory_os_alloc.h"
31 #include "mali_memory_block_alloc.h"
32
33 /* session->memory_lock must be held when calling this function */
34 static void mali_mem_release(mali_mem_allocation *descriptor)
35 {
36         MALI_DEBUG_ASSERT_POINTER(descriptor);
37         MALI_DEBUG_ASSERT_LOCK_HELD(descriptor->session->memory_lock);
38
39         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
40
41         switch (descriptor->type) {
42         case MALI_MEM_OS:
43                 mali_mem_os_release(descriptor);
44                 break;
45         case MALI_MEM_DMA_BUF:
46 #if defined(CONFIG_DMA_SHARED_BUFFER)
47                 mali_mem_dma_buf_release(descriptor);
48 #endif
49                 break;
50         case MALI_MEM_UMP:
51 #if defined(CONFIG_MALI400_UMP)
52                 mali_mem_ump_release(descriptor);
53 #endif
54                 break;
55         case MALI_MEM_EXTERNAL:
56                 mali_mem_external_release(descriptor);
57                 break;
58         case MALI_MEM_BLOCK:
59                 mali_mem_block_release(descriptor);
60                 break;
61         }
62 }
63
64 static void mali_mem_vma_open(struct vm_area_struct * vma)
65 {
66         mali_mem_allocation *descriptor = (mali_mem_allocation*)vma->vm_private_data;
67         MALI_DEBUG_PRINT(4, ("Open called on vma %p\n", vma));
68
69         descriptor->cpu_mapping.ref++;
70
71         return;
72 }
73
74 static void mali_mem_vma_close(struct vm_area_struct *vma)
75 {
76         mali_mem_allocation *descriptor;
77         struct mali_session_data *session;
78         mali_mem_virt_cpu_mapping *mapping;
79
80         MALI_DEBUG_PRINT(3, ("Close called on vma %p\n", vma));
81
82         descriptor = (mali_mem_allocation*)vma->vm_private_data;
83         BUG_ON(!descriptor);
84
85         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
86
87         mapping = &descriptor->cpu_mapping;
88         BUG_ON(0 == mapping->ref);
89
90         mapping->ref--;
91         if (0 != mapping->ref) {
92                 MALI_DEBUG_PRINT(3, ("Ignoring this close, %d references still exists\n", mapping->ref));
93                 return;
94         }
95
96         session = descriptor->session;
97
98         mali_descriptor_mapping_free(session->descriptor_mapping, descriptor->id);
99
100         _mali_osk_mutex_wait(session->memory_lock);
101         mali_mem_release(descriptor);
102         _mali_osk_mutex_signal(session->memory_lock);
103
104         mali_mem_descriptor_destroy(descriptor);
105 }
106
107 static int mali_kernel_memory_cpu_page_fault_handler(struct vm_area_struct *vma, struct vm_fault *vmf)
108 {
109         void __user * address;
110         mali_mem_allocation *descriptor;
111
112         address = vmf->virtual_address;
113         descriptor = (mali_mem_allocation *)vma->vm_private_data;
114
115         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
116
117         /*
118          * We always fail the call since all memory is pre-faulted when assigned to the process.
119          * Only the Mali cores can use page faults to extend buffers.
120         */
121
122         MALI_DEBUG_PRINT(1, ("Page-fault in Mali memory region caused by the CPU.\n"));
123         MALI_DEBUG_PRINT(1, ("Tried to access %p (process local virtual address) which is not currently mapped to any Mali memory.\n", (void*)address));
124
125         MALI_IGNORE(address);
126         MALI_IGNORE(descriptor);
127
128         return VM_FAULT_SIGBUS;
129 }
130
131 struct vm_operations_struct mali_kernel_vm_ops = {
132         .open = mali_mem_vma_open,
133         .close = mali_mem_vma_close,
134         .fault = mali_kernel_memory_cpu_page_fault_handler
135 };
136
137 /** @note munmap handler is done by vma close handler */
138 int mali_mmap(struct file *filp, struct vm_area_struct *vma)
139 {
140         struct mali_session_data *session;
141         mali_mem_allocation *descriptor;
142         u32 size = vma->vm_end - vma->vm_start;
143         u32 mali_addr = vma->vm_pgoff << PAGE_SHIFT;
144
145         session = (struct mali_session_data *)filp->private_data;
146         if (NULL == session) {
147                 MALI_PRINT_ERROR(("mmap called without any session data available\n"));
148                 return -EFAULT;
149         }
150
151         MALI_DEBUG_PRINT(4, ("MMap() handler: start=0x%08X, phys=0x%08X, size=0x%08X vma->flags 0x%08x\n",
152                              (unsigned int)vma->vm_start, (unsigned int)(vma->vm_pgoff << PAGE_SHIFT),
153                              (unsigned int)(vma->vm_end - vma->vm_start), vma->vm_flags));
154
155         /* Set some bits which indicate that, the memory is IO memory, meaning
156          * that no paging is to be performed and the memory should not be
157          * included in crash dumps. And that the memory is reserved, meaning
158          * that it's present and can never be paged out (see also previous
159          * entry)
160          */
161         vma->vm_flags |= VM_IO;
162         vma->vm_flags |= VM_DONTCOPY;
163         vma->vm_flags |= VM_PFNMAP;
164 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
165         vma->vm_flags |= VM_RESERVED;
166 #else
167         vma->vm_flags |= VM_DONTDUMP;
168         vma->vm_flags |= VM_DONTEXPAND;
169 #endif
170
171         /* For CTS4.4_mr3 security case
172          * force read mapping fail if meet KBASE_REG_COOKIE_MTP or KBASE_REG_COOKIE_TB
173          */
174 #define KBASE_REG_COOKIE_MTP 1
175 #define KBASE_REG_COOKIE_TB 2
176         if ((vma->vm_pgoff == KBASE_REG_COOKIE_MTP) || (vma->vm_pgoff == KBASE_REG_COOKIE_TB)) {
177                 vma->vm_flags &= ~(VM_READ | VM_MAYREAD);
178         }
179
180         vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
181         vma->vm_ops = &mali_kernel_vm_ops; /* Operations used on any memory system */
182
183         descriptor = mali_mem_block_alloc(mali_addr, size, vma, session);
184         if (NULL == descriptor) {
185                 descriptor = mali_mem_os_alloc(mali_addr, size, vma, session);
186                 if (NULL == descriptor) {
187                         MALI_DEBUG_PRINT(3, ("MMAP failed\n"));
188                         return -ENOMEM;
189                 }
190         }
191
192         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
193
194         vma->vm_private_data = (void*)descriptor;
195
196         /* Put on descriptor map */
197         if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session->descriptor_mapping, descriptor, &descriptor->id)) {
198                 _mali_osk_mutex_wait(session->memory_lock);
199                 mali_mem_os_release(descriptor);
200                 _mali_osk_mutex_signal(session->memory_lock);
201                 return -EFAULT;
202         }
203
204         return 0;
205 }
206
207
208 /* Prepare memory descriptor */
209 mali_mem_allocation *mali_mem_descriptor_create(struct mali_session_data *session, mali_mem_type type)
210 {
211         mali_mem_allocation *descriptor;
212
213         descriptor = (mali_mem_allocation*)kzalloc(sizeof(mali_mem_allocation), GFP_KERNEL);
214         if (NULL == descriptor) {
215                 MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: descriptor was NULL\n"));
216                 return NULL;
217         }
218
219         MALI_DEBUG_CODE(descriptor->magic = MALI_MEM_ALLOCATION_VALID_MAGIC);
220
221         descriptor->flags = 0;
222         descriptor->type = type;
223         descriptor->session = session;
224
225         return descriptor;
226 }
227
228 void mali_mem_descriptor_destroy(mali_mem_allocation *descriptor)
229 {
230         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
231         MALI_DEBUG_CODE(descriptor->magic = MALI_MEM_ALLOCATION_FREED_MAGIC);
232
233         kfree(descriptor);
234 }
235
236 _mali_osk_errcode_t mali_mem_mali_map_prepare(mali_mem_allocation *descriptor)
237 {
238         u32 size = descriptor->size;
239         struct mali_session_data *session = descriptor->session;
240
241         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
242
243         /* Map dma-buf into this session's page tables */
244
245         if (descriptor->flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) {
246                 size += MALI_MMU_PAGE_SIZE;
247         }
248
249         return mali_mmu_pagedir_map(session->page_directory, descriptor->mali_mapping.addr, size);
250 }
251
252 extern void mali_pause_lock(void);
253 extern void mali_pause_unlock(void);
254
255 void mali_mem_mali_map_free(mali_mem_allocation *descriptor)
256 {
257         u32 size = descriptor->size;
258         struct mali_session_data *session = descriptor->session;
259
260         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
261
262         if (descriptor->flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) {
263                 size += MALI_MMU_PAGE_SIZE;
264         }
265
266         mali_pause_lock();
267
268         /* Umap and flush L2 */
269         mali_mmu_pagedir_unmap(session->page_directory, descriptor->mali_mapping.addr, descriptor->size);
270
271         mali_scheduler_zap_all_active(session);
272
273         mali_pause_unlock();
274 }
275
276 u32 _mali_ukk_report_memory_usage(void)
277 {
278         u32 sum = 0;
279
280         sum += mali_mem_block_allocator_stat();
281         sum += mali_mem_os_stat();
282
283         return sum;
284 }
285
286 /**
287  * Per-session memory descriptor mapping table sizes
288  */
289 #define MALI_MEM_DESCRIPTORS_INIT 64
290 #define MALI_MEM_DESCRIPTORS_MAX 65536
291
292 _mali_osk_errcode_t mali_memory_session_begin(struct mali_session_data * session_data)
293 {
294         MALI_DEBUG_PRINT(5, ("Memory session begin\n"));
295
296         /* Create descriptor mapping table */
297         session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX);
298
299         if (NULL == session_data->descriptor_mapping) {
300                 MALI_ERROR(_MALI_OSK_ERR_NOMEM);
301         }
302
303         session_data->memory_lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
304                                     _MALI_OSK_LOCK_ORDER_MEM_SESSION);
305
306         if (NULL == session_data->memory_lock) {
307                 mali_descriptor_mapping_destroy(session_data->descriptor_mapping);
308                 _mali_osk_free(session_data);
309                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
310         }
311
312         session_data->pid = _mali_osk_get_pid();
313
314         MALI_DEBUG_PRINT(5, ("MMU session begin: success\n"));
315         MALI_SUCCESS;
316 }
317
318 /** @brief Callback function that releases memory
319  *
320  * session->memory_lock must be held when calling this function.
321  */
322 static void descriptor_table_cleanup_callback(int descriptor_id, void* map_target)
323 {
324         mali_mem_allocation *descriptor;
325
326         descriptor = (mali_mem_allocation*)map_target;
327
328         MALI_DEBUG_ASSERT_LOCK_HELD(descriptor->session->memory_lock);
329
330         MALI_DEBUG_PRINT(3, ("Cleanup of descriptor %d mapping to 0x%x in descriptor table\n", descriptor_id, map_target));
331         MALI_DEBUG_ASSERT(descriptor);
332
333         mali_mem_release(descriptor);
334         mali_mem_descriptor_destroy(descriptor);
335 }
336
337 void mali_memory_session_end(struct mali_session_data *session)
338 {
339         MALI_DEBUG_PRINT(3, ("MMU session end\n"));
340
341         if (NULL == session) {
342                 MALI_DEBUG_PRINT(1, ("No session data found during session end\n"));
343                 return;
344         }
345
346         /* Lock the session so we can modify the memory list */
347         _mali_osk_mutex_wait(session->memory_lock);
348
349         /* Free all allocations still in the descriptor map, and terminate the map */
350         if (NULL != session->descriptor_mapping) {
351                 mali_descriptor_mapping_call_for_each(session->descriptor_mapping, descriptor_table_cleanup_callback);
352                 mali_descriptor_mapping_destroy(session->descriptor_mapping);
353                 session->descriptor_mapping = NULL;
354         }
355
356         _mali_osk_mutex_signal(session->memory_lock);
357
358         /* Free the lock */
359         _mali_osk_mutex_term(session->memory_lock);
360
361         return;
362 }
363
364 _mali_osk_errcode_t mali_memory_initialize(void)
365 {
366         return mali_mem_os_init();
367 }
368
369 void mali_memory_terminate(void)
370 {
371         mali_mem_os_term();
372         mali_mem_block_allocator_destroy(NULL);
373 }
374
375 _mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args )
376 {
377         MALI_DEBUG_ASSERT_POINTER(args);
378         MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
379 #ifdef SPRD_MEM_OPT_PAGE_TABLE_SHRINK
380         args->memory_size       = ARCH_MALI_MEMORY_SIZE_DEFAULT;
381         args->mali_address_base = ARCH_MALI_MEMORY_BASE_DEFAULT;
382 #else
383         args->memory_size = 2 * 1024 * 1024 * 1024UL; /* 2GB address space */
384         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) */
385 #endif
386         MALI_SUCCESS;
387 }
388
389 _mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args )
390 {
391         MALI_DEBUG_ASSERT_POINTER(args);
392         MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
393         MALI_SUCCESS;
394 }
395
396 u32 _mali_kernel_memory_dump_state(char* buf, u32 size)
397 {
398         int n = 0;
399
400         struct mali_session_data *session, *tmp;
401
402         mali_session_lock();
403         MALI_SESSION_FOREACH(session, tmp, link)
404         {
405                 int i;
406                 u32 sum_gl = 0;
407
408                 _mali_osk_mutex_wait(session->memory_lock);
409
410                 _mali_osk_mutex_rw_wait(session->descriptor_mapping->lock, _MALI_OSK_LOCKMODE_RO);
411                 /* id 0 is skipped as it's an reserved ID not mapping to anything */
412                 for (i = 1; i < session->descriptor_mapping->current_nr_mappings; ++i) {
413                         if (_mali_osk_test_bit(i, session->descriptor_mapping->table->usage)) {
414                                 mali_mem_allocation* descriptor = (mali_mem_allocation*)session->descriptor_mapping->table->mappings[i];
415                                 switch(descriptor->type)
416                                 {
417                                 case MALI_MEM_OS:
418                                         sum_gl += descriptor->size;
419 //                                      n += _mali_osk_snprintf(buf + n, size - n, "\t%-8s\t0x%08x\n", "GL", descriptor->size);
420                                         break;
421                                 default:
422                                         ;
423                                 }
424                         }
425                 }
426                 _mali_osk_mutex_rw_signal(session->descriptor_mapping->lock, _MALI_OSK_LOCKMODE_RO);
427
428                 _mali_osk_mutex_signal(session->memory_lock);
429
430                 n += _mali_osk_snprintf(buf + n, size - n, "%8d\t0x%08x\n", session->pid, sum_gl);
431         }
432         mali_session_unlock();
433
434         return n;
435 }
436