UPSTREAM: DT/arm,gic-v3: Documment PPI partition support
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / linux / mali_memory.c
1 /*
2  * Copyright (C) 2013-2014 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 #include "mali_osk.h"
21 #include "mali_osk_mali.h"
22 #include "mali_kernel_linux.h"
23 #include "mali_scheduler.h"
24 #include "mali_executor.h"
25 #include "mali_kernel_descriptor_mapping.h"
26
27 #include "mali_memory.h"
28 #include "mali_memory_dma_buf.h"
29 #include "mali_memory_os_alloc.h"
30 #include "mali_memory_block_alloc.h"
31
32 extern unsigned int mali_dedicated_mem_size;
33 extern unsigned int mali_shared_mem_size;
34
35 /* session->memory_lock must be held when calling this function */
36 static void mali_mem_release(mali_mem_allocation *descriptor)
37 {
38         MALI_DEBUG_ASSERT_POINTER(descriptor);
39         MALI_DEBUG_ASSERT_LOCK_HELD(descriptor->session->memory_lock);
40
41         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
42
43         switch (descriptor->type) {
44         case MALI_MEM_OS:
45                 mali_mem_os_release(descriptor);
46                 break;
47         case MALI_MEM_DMA_BUF:
48 #if defined(CONFIG_DMA_SHARED_BUFFER)
49                 mali_mem_dma_buf_release(descriptor);
50 #endif
51                 break;
52         case MALI_MEM_UMP:
53 #if defined(CONFIG_MALI400_UMP)
54                 mali_mem_ump_release(descriptor);
55 #endif
56                 break;
57         case MALI_MEM_EXTERNAL:
58                 mali_mem_external_release(descriptor);
59                 break;
60         case MALI_MEM_BLOCK:
61                 mali_mem_block_release(descriptor);
62                 break;
63         default:
64                 MALI_DEBUG_PRINT(1, ("mem type %d is not in the mali_mem_type enum.\n", descriptor->type));
65                 break;
66         }
67 }
68
69 static void mali_mem_vma_open(struct vm_area_struct *vma)
70 {
71         mali_mem_allocation *descriptor = (mali_mem_allocation *)vma->vm_private_data;
72         MALI_DEBUG_PRINT(4, ("Open called on vma %p\n", vma));
73
74         descriptor->cpu_mapping.ref++;
75
76         return;
77 }
78
79 static void mali_mem_vma_close(struct vm_area_struct *vma)
80 {
81         mali_mem_allocation *descriptor;
82         struct mali_session_data *session;
83         mali_mem_virt_cpu_mapping *mapping;
84
85         MALI_DEBUG_PRINT(3, ("Close called on vma %p\n", vma));
86
87         descriptor = (mali_mem_allocation *)vma->vm_private_data;
88         BUG_ON(!descriptor);
89
90         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
91
92         mapping = &descriptor->cpu_mapping;
93         BUG_ON(0 == mapping->ref);
94
95         mapping->ref--;
96         if (0 != mapping->ref) {
97                 MALI_DEBUG_PRINT(3, ("Ignoring this close, %d references still exists\n", mapping->ref));
98                 return;
99         }
100
101         session = descriptor->session;
102
103         mali_descriptor_mapping_free(session->descriptor_mapping, descriptor->id);
104
105         _mali_osk_mutex_wait(session->memory_lock);
106         mali_mem_release(descriptor);
107         _mali_osk_mutex_signal(session->memory_lock);
108
109         mali_mem_descriptor_destroy(descriptor);
110 }
111
112 static int mali_kernel_memory_cpu_page_fault_handler(struct vm_area_struct *vma, struct vm_fault *vmf)
113 {
114         void __user *address;
115         mali_mem_allocation *descriptor;
116
117         address = vmf->virtual_address;
118         descriptor = (mali_mem_allocation *)vma->vm_private_data;
119
120         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
121
122         /*
123          * We always fail the call since all memory is pre-faulted when assigned to the process.
124          * Only the Mali cores can use page faults to extend buffers.
125         */
126
127         MALI_DEBUG_PRINT(1, ("Page-fault in Mali memory region caused by the CPU.\n"));
128         MALI_DEBUG_PRINT(1, ("Tried to access %p (process local virtual address) which is not currently mapped to any Mali memory.\n", (void *)address));
129
130         MALI_IGNORE(address);
131         MALI_IGNORE(descriptor);
132
133         return VM_FAULT_SIGBUS;
134 }
135
136 static struct vm_operations_struct mali_kernel_vm_ops = {
137         .open = mali_mem_vma_open,
138         .close = mali_mem_vma_close,
139         .fault = mali_kernel_memory_cpu_page_fault_handler
140 };
141
142 /** @note munmap handler is done by vma close handler */
143 int mali_mmap(struct file *filp, struct vm_area_struct *vma)
144 {
145         struct mali_session_data *session;
146         mali_mem_allocation *descriptor;
147         u32 size = vma->vm_end - vma->vm_start;
148         u32 mali_addr = vma->vm_pgoff << PAGE_SHIFT;
149
150         session = (struct mali_session_data *)filp->private_data;
151         if (NULL == session) {
152                 MALI_PRINT_ERROR(("mmap called without any session data available\n"));
153                 return -EFAULT;
154         }
155
156         MALI_DEBUG_PRINT(4, ("MMap() handler: start=0x%08X, phys=0x%08X, size=0x%08X vma->flags 0x%08x\n",
157                              (unsigned int)vma->vm_start, (unsigned int)(vma->vm_pgoff << PAGE_SHIFT),
158                              (unsigned int)(vma->vm_end - vma->vm_start), vma->vm_flags));
159
160         /* Set some bits which indicate that, the memory is IO memory, meaning
161          * that no paging is to be performed and the memory should not be
162          * included in crash dumps. And that the memory is reserved, meaning
163          * that it's present and can never be paged out (see also previous
164          * entry)
165          */
166         vma->vm_flags |= VM_IO;
167         vma->vm_flags |= VM_DONTCOPY;
168         vma->vm_flags |= VM_PFNMAP;
169 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
170         vma->vm_flags |= VM_RESERVED;
171 #else
172         vma->vm_flags |= VM_DONTDUMP;
173         vma->vm_flags |= VM_DONTEXPAND;
174 #endif
175
176         vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
177         vma->vm_ops = &mali_kernel_vm_ops; /* Operations used on any memory system */
178
179         descriptor = mali_mem_block_alloc(mali_addr, size, vma, session);
180         if (NULL == descriptor) {
181                 descriptor = mali_mem_os_alloc(mali_addr, size, vma, session);
182                 if (NULL == descriptor) {
183                         MALI_DEBUG_PRINT(3, ("MMAP failed\n"));
184                         return -ENOMEM;
185                 }
186         }
187
188         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
189
190         vma->vm_private_data = (void *)descriptor;
191
192         /* Put on descriptor map */
193         if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session->descriptor_mapping, descriptor, &descriptor->id)) {
194                 _mali_osk_mutex_wait(session->memory_lock);
195                 if (MALI_MEM_OS == descriptor->type) {
196                         mali_mem_os_release(descriptor);
197                 } else if (MALI_MEM_BLOCK == descriptor->type) {
198                         mali_mem_block_release(descriptor);
199                 }
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 void mali_mem_mali_map_free(mali_mem_allocation *descriptor)
253 {
254         u32 size = descriptor->size;
255         struct mali_session_data *session = descriptor->session;
256
257         MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic);
258
259         if (descriptor->flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) {
260                 size += MALI_MMU_PAGE_SIZE;
261         }
262
263         /* Umap and flush L2 */
264         mali_mmu_pagedir_unmap(session->page_directory, descriptor->mali_mapping.addr, descriptor->size);
265
266         mali_executor_zap_all_active(session);
267 }
268
269 u32 _mali_ukk_report_memory_usage(void)
270 {
271         u32 sum = 0;
272
273         sum += mali_mem_block_allocator_stat();
274         sum += mali_mem_os_stat();
275
276         return sum;
277 }
278
279 u32 _mali_ukk_report_total_memory_size(void)
280 {
281         return mali_dedicated_mem_size + mali_shared_mem_size;
282 }
283
284
285 /**
286  * Per-session memory descriptor mapping table sizes
287  */
288 #define MALI_MEM_DESCRIPTORS_INIT 64
289 #define MALI_MEM_DESCRIPTORS_MAX 65536
290
291 _mali_osk_errcode_t mali_memory_session_begin(struct mali_session_data *session_data)
292 {
293         MALI_DEBUG_PRINT(5, ("Memory session begin\n"));
294
295         /* Create descriptor mapping table */
296         session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX);
297
298         if (NULL == session_data->descriptor_mapping) {
299                 MALI_ERROR(_MALI_OSK_ERR_NOMEM);
300         }
301
302         session_data->memory_lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
303                                     _MALI_OSK_LOCK_ORDER_MEM_SESSION);
304
305         if (NULL == session_data->memory_lock) {
306                 mali_descriptor_mapping_destroy(session_data->descriptor_mapping);
307                 _mali_osk_free(session_data);
308                 MALI_ERROR(_MALI_OSK_ERR_FAULT);
309         }
310
311         MALI_DEBUG_PRINT(5, ("MMU session begin: success\n"));
312         MALI_SUCCESS;
313 }
314
315 /** @brief Callback function that releases memory
316  *
317  * session->memory_lock must be held when calling this function.
318  */
319 static void descriptor_table_cleanup_callback(int descriptor_id, void *map_target)
320 {
321         mali_mem_allocation *descriptor;
322
323         descriptor = (mali_mem_allocation *)map_target;
324
325         MALI_DEBUG_ASSERT_LOCK_HELD(descriptor->session->memory_lock);
326
327         MALI_DEBUG_PRINT(3, ("Cleanup of descriptor %d mapping to 0x%x in descriptor table\n", descriptor_id, map_target));
328         MALI_DEBUG_ASSERT(descriptor);
329
330         mali_mem_release(descriptor);
331         mali_mem_descriptor_destroy(descriptor);
332 }
333
334 void mali_memory_session_end(struct mali_session_data *session)
335 {
336         MALI_DEBUG_PRINT(3, ("MMU session end\n"));
337
338         if (NULL == session) {
339                 MALI_DEBUG_PRINT(1, ("No session data found during session end\n"));
340                 return;
341         }
342
343         /* Lock the session so we can modify the memory list */
344         _mali_osk_mutex_wait(session->memory_lock);
345
346         /* Free all allocations still in the descriptor map, and terminate the map */
347         if (NULL != session->descriptor_mapping) {
348                 mali_descriptor_mapping_call_for_each(session->descriptor_mapping, descriptor_table_cleanup_callback);
349                 mali_descriptor_mapping_destroy(session->descriptor_mapping);
350                 session->descriptor_mapping = NULL;
351         }
352
353         _mali_osk_mutex_signal(session->memory_lock);
354
355         /* Free the lock */
356         _mali_osk_mutex_term(session->memory_lock);
357
358         return;
359 }
360
361 _mali_osk_errcode_t mali_memory_initialize(void)
362 {
363         return mali_mem_os_init();
364 }
365
366 void mali_memory_terminate(void)
367 {
368         mali_mem_os_term();
369         mali_mem_block_allocator_destroy(NULL);
370 }