UPSTREAM: DT/arm,gic-v3: Documment PPI partition support
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / linux / mali_memory_dma_buf.c
1 /*
2  * Copyright (C) 2012-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/fs.h>      /* file system operations */
12 #include <asm/uaccess.h>        /* user space access */
13 #include <linux/dma-buf.h>
14 #include <linux/scatterlist.h>
15 #include <linux/rbtree.h>
16 #include <linux/platform_device.h>
17 #include <linux/wait.h>
18 #include <linux/sched.h>
19 #include <linux/mutex.h>
20
21 #include "mali_ukk.h"
22 #include "mali_osk.h"
23 #include "mali_kernel_common.h"
24 #include "mali_session.h"
25 #include "mali_kernel_linux.h"
26
27 #include "mali_memory.h"
28 #include "mali_memory_dma_buf.h"
29
30 #include "mali_pp_job.h"
31
32 static void mali_dma_buf_unmap(struct mali_dma_buf_attachment *mem);
33
34 struct mali_dma_buf_attachment {
35         struct dma_buf *buf;
36         struct dma_buf_attachment *attachment;
37         struct sg_table *sgt;
38         struct mali_session_data *session;
39         int map_ref;
40         struct mutex map_lock;
41         mali_bool is_mapped;
42         wait_queue_head_t wait_queue;
43 };
44
45 static void mali_dma_buf_release(struct mali_dma_buf_attachment *mem)
46 {
47         MALI_DEBUG_PRINT(3, ("Mali DMA-buf: release attachment %p\n", mem));
48
49         MALI_DEBUG_ASSERT_POINTER(mem);
50         MALI_DEBUG_ASSERT_POINTER(mem->attachment);
51         MALI_DEBUG_ASSERT_POINTER(mem->buf);
52
53 #if defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
54         /* We mapped implicitly on attach, so we need to unmap on release */
55         mali_dma_buf_unmap(mem);
56 #endif
57
58         /* Wait for buffer to become unmapped */
59         wait_event(mem->wait_queue, !mem->is_mapped);
60         MALI_DEBUG_ASSERT(!mem->is_mapped);
61
62         dma_buf_detach(mem->buf, mem->attachment);
63         dma_buf_put(mem->buf);
64
65         _mali_osk_free(mem);
66 }
67
68 void mali_mem_dma_buf_release(mali_mem_allocation *descriptor)
69 {
70         struct mali_dma_buf_attachment *mem = descriptor->dma_buf.attachment;
71
72         mali_dma_buf_release(mem);
73 }
74
75 /*
76  * Map DMA buf attachment \a mem into \a session at virtual address \a virt.
77  */
78 static int mali_dma_buf_map(struct mali_dma_buf_attachment *mem, struct mali_session_data *session, u32 virt, u32 flags)
79 {
80         struct mali_page_directory *pagedir;
81         struct scatterlist *sg;
82         int i;
83
84         MALI_DEBUG_ASSERT_POINTER(mem);
85         MALI_DEBUG_ASSERT_POINTER(session);
86         MALI_DEBUG_ASSERT(mem->session == session);
87
88         mutex_lock(&mem->map_lock);
89
90         mem->map_ref++;
91
92         MALI_DEBUG_PRINT(5, ("Mali DMA-buf: map attachment %p, new map_ref = %d\n", mem, mem->map_ref));
93
94         if (1 == mem->map_ref) {
95                 /* First reference taken, so we need to map the dma buf */
96                 MALI_DEBUG_ASSERT(!mem->is_mapped);
97
98                 pagedir = mali_session_get_page_directory(session);
99                 MALI_DEBUG_ASSERT_POINTER(pagedir);
100
101                 mem->sgt = dma_buf_map_attachment(mem->attachment, DMA_BIDIRECTIONAL);
102                 if (IS_ERR_OR_NULL(mem->sgt)) {
103                         MALI_DEBUG_PRINT_ERROR(("Failed to map dma-buf attachment\n"));
104                         return -EFAULT;
105                 }
106
107                 for_each_sg(mem->sgt->sgl, sg, mem->sgt->nents, i) {
108                         u32 size = sg_dma_len(sg);
109                         dma_addr_t phys = sg_dma_address(sg);
110
111                         /* sg must be page aligned. */
112                         MALI_DEBUG_ASSERT(0 == size % MALI_MMU_PAGE_SIZE);
113                         MALI_DEBUG_ASSERT(0 == (phys & ~(uintptr_t)0xFFFFFFFF));
114
115                         mali_mmu_pagedir_update(pagedir, virt, phys, size, MALI_MMU_FLAGS_DEFAULT);
116
117                         virt += size;
118                 }
119
120                 if (flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) {
121                         u32 guard_phys;
122                         MALI_DEBUG_PRINT(7, ("Mapping in extra guard page\n"));
123
124                         guard_phys = sg_dma_address(mem->sgt->sgl);
125                         mali_mmu_pagedir_update(pagedir, virt, guard_phys, MALI_MMU_PAGE_SIZE, MALI_MMU_FLAGS_DEFAULT);
126                 }
127
128                 mem->is_mapped = MALI_TRUE;
129                 mutex_unlock(&mem->map_lock);
130
131                 /* Wake up any thread waiting for buffer to become mapped */
132                 wake_up_all(&mem->wait_queue);
133         } else {
134                 MALI_DEBUG_ASSERT(mem->is_mapped);
135                 mutex_unlock(&mem->map_lock);
136         }
137
138         return 0;
139 }
140
141 static void mali_dma_buf_unmap(struct mali_dma_buf_attachment *mem)
142 {
143         MALI_DEBUG_ASSERT_POINTER(mem);
144         MALI_DEBUG_ASSERT_POINTER(mem->attachment);
145         MALI_DEBUG_ASSERT_POINTER(mem->buf);
146
147         mutex_lock(&mem->map_lock);
148
149         mem->map_ref--;
150
151         MALI_DEBUG_PRINT(5, ("Mali DMA-buf: unmap attachment %p, new map_ref = %d\n", mem, mem->map_ref));
152
153         if (0 == mem->map_ref) {
154                 dma_buf_unmap_attachment(mem->attachment, mem->sgt, DMA_BIDIRECTIONAL);
155
156                 mem->is_mapped = MALI_FALSE;
157         }
158
159         mutex_unlock(&mem->map_lock);
160
161         /* Wake up any thread waiting for buffer to become unmapped */
162         wake_up_all(&mem->wait_queue);
163 }
164
165 #if !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
166 int mali_dma_buf_map_job(struct mali_pp_job *job)
167 {
168         mali_mem_allocation *descriptor;
169         struct mali_dma_buf_attachment *mem;
170         _mali_osk_errcode_t err;
171         int i;
172         int ret = 0;
173         u32 num_memory_cookies;
174         struct mali_session_data *session;
175
176         MALI_DEBUG_ASSERT_POINTER(job);
177
178         num_memory_cookies = mali_pp_job_num_memory_cookies(job);
179
180         session = mali_pp_job_get_session(job);
181
182         MALI_DEBUG_ASSERT_POINTER(session);
183
184         mali_session_memory_lock(session);
185
186         for (i = 0; i < num_memory_cookies; i++) {
187                 u32 cookie = mali_pp_job_get_memory_cookie(job, i);
188
189                 if (0 == cookie) {
190                         /* 0 is not a valid cookie */
191                         MALI_DEBUG_ASSERT(NULL ==
192                                           mali_pp_job_get_dma_buf(job, i));
193                         continue;
194                 }
195
196                 MALI_DEBUG_ASSERT(0 < cookie);
197
198                 err = mali_descriptor_mapping_get(
199                               mali_pp_job_get_session(job)->descriptor_mapping,
200                               cookie, (void **)&descriptor);
201
202                 if (_MALI_OSK_ERR_OK != err) {
203                         MALI_DEBUG_PRINT_ERROR(("Mali DMA-buf: Failed to get descriptor for cookie %d\n", cookie));
204                         ret = -EFAULT;
205                         MALI_DEBUG_ASSERT(NULL ==
206                                           mali_pp_job_get_dma_buf(job, i));
207                         continue;
208                 }
209
210                 if (MALI_MEM_DMA_BUF != descriptor->type) {
211                         /* Not a DMA-buf */
212                         MALI_DEBUG_ASSERT(NULL ==
213                                           mali_pp_job_get_dma_buf(job, i));
214                         continue;
215                 }
216
217                 mem = descriptor->dma_buf.attachment;
218
219                 MALI_DEBUG_ASSERT_POINTER(mem);
220                 MALI_DEBUG_ASSERT(mem->session == mali_pp_job_get_session(job));
221
222                 err = mali_dma_buf_map(mem, mem->session, descriptor->mali_mapping.addr, descriptor->flags);
223                 if (0 != err) {
224                         MALI_DEBUG_PRINT_ERROR(("Mali DMA-buf: Failed to map dma-buf for cookie %d at mali address %x\b",
225                                                 cookie, descriptor->mali_mapping.addr));
226                         ret = -EFAULT;
227                         MALI_DEBUG_ASSERT(NULL ==
228                                           mali_pp_job_get_dma_buf(job, i));
229                         continue;
230                 }
231
232                 /* Add mem to list of DMA-bufs mapped for this job */
233                 mali_pp_job_set_dma_buf(job, i, mem);
234         }
235
236         mali_session_memory_unlock(session);
237
238         return ret;
239 }
240
241 void mali_dma_buf_unmap_job(struct mali_pp_job *job)
242 {
243         u32 i;
244         u32 num_dma_bufs = mali_pp_job_num_dma_bufs(job);
245
246         for (i = 0; i < num_dma_bufs; i++) {
247                 struct mali_dma_buf_attachment *mem;
248
249                 mem = mali_pp_job_get_dma_buf(job, i);
250                 if (NULL != mem) {
251                         mali_dma_buf_unmap(mem);
252                         mali_pp_job_set_dma_buf(job, i, NULL);
253                 }
254         }
255 }
256 #endif /* !CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH */
257
258 int mali_attach_dma_buf(struct mali_session_data *session, _mali_uk_attach_dma_buf_s __user *user_arg)
259 {
260         struct dma_buf *buf;
261         struct mali_dma_buf_attachment *mem;
262         _mali_uk_attach_dma_buf_s args;
263         mali_mem_allocation *descriptor;
264         int md;
265         int fd;
266
267         /* Get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
268         if (0 != copy_from_user(&args, (void __user *)user_arg, sizeof(_mali_uk_attach_dma_buf_s))) {
269                 return -EFAULT;
270         }
271
272         if (args.mali_address & ~PAGE_MASK) {
273                 MALI_DEBUG_PRINT_ERROR(("Requested address (0x%08x) is not page aligned\n", args.mali_address));
274                 return -EINVAL;
275         }
276
277         if (args.mali_address >= args.mali_address + args.size) {
278                 MALI_DEBUG_PRINT_ERROR(("Requested address and size (0x%08x + 0x%08x) is too big\n", args.mali_address, args.size));
279                 return -EINVAL;
280         }
281
282         fd = args.mem_fd;
283
284         buf = dma_buf_get(fd);
285         if (IS_ERR_OR_NULL(buf)) {
286                 MALI_DEBUG_PRINT_ERROR(("Failed to get dma-buf from fd: %d\n", fd));
287                 return PTR_RET(buf);
288         }
289
290         /* Currently, mapping of the full buffer are supported. */
291         if (args.size != buf->size) {
292                 MALI_DEBUG_PRINT_ERROR(("dma-buf size doesn't match mapping size.\n"));
293                 dma_buf_put(buf);
294                 return -EINVAL;
295         }
296
297         mem = _mali_osk_calloc(1, sizeof(struct mali_dma_buf_attachment));
298         if (NULL == mem) {
299                 MALI_DEBUG_PRINT_ERROR(("Failed to allocate dma-buf tracing struct\n"));
300                 dma_buf_put(buf);
301                 return -ENOMEM;
302         }
303
304         mem->buf = buf;
305         mem->session = session;
306         mem->map_ref = 0;
307         mutex_init(&mem->map_lock);
308         init_waitqueue_head(&mem->wait_queue);
309
310         mem->attachment = dma_buf_attach(mem->buf, &mali_platform_device->dev);
311         if (NULL == mem->attachment) {
312                 MALI_DEBUG_PRINT_ERROR(("Failed to attach to dma-buf %d\n", fd));
313                 dma_buf_put(mem->buf);
314                 _mali_osk_free(mem);
315                 return -EFAULT;
316         }
317
318         /* Set up Mali memory descriptor */
319         descriptor = mali_mem_descriptor_create(session, MALI_MEM_DMA_BUF);
320         if (NULL == descriptor) {
321                 MALI_DEBUG_PRINT_ERROR(("Failed to allocate descriptor dma-buf %d\n", fd));
322                 mali_dma_buf_release(mem);
323                 return -ENOMEM;
324         }
325
326         descriptor->size = args.size;
327         descriptor->mali_mapping.addr = args.mali_address;
328
329         descriptor->dma_buf.attachment = mem;
330
331         descriptor->flags |= MALI_MEM_FLAG_DONT_CPU_MAP;
332         if (args.flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) {
333                 descriptor->flags = MALI_MEM_FLAG_MALI_GUARD_PAGE;
334         }
335
336         mali_session_memory_lock(session);
337
338         /* Map dma-buf into this session's page tables */
339         if (_MALI_OSK_ERR_OK != mali_mem_mali_map_prepare(descriptor)) {
340                 mali_session_memory_unlock(session);
341                 MALI_DEBUG_PRINT_ERROR(("Failed to map dma-buf on Mali\n"));
342                 mali_mem_descriptor_destroy(descriptor);
343                 mali_dma_buf_release(mem);
344                 return -ENOMEM;
345         }
346
347 #if defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
348         /* Map memory into session's Mali virtual address space. */
349
350         if (0 != mali_dma_buf_map(mem, session, descriptor->mali_mapping.addr, descriptor->flags)) {
351                 mali_mem_mali_map_free(descriptor);
352                 mali_session_memory_unlock(session);
353
354                 MALI_DEBUG_PRINT_ERROR(("Failed to map dma-buf %d into Mali address space\n", fd));
355                 mali_mem_descriptor_destroy(descriptor);
356                 mali_dma_buf_release(mem);
357                 return -ENOMEM;
358         }
359
360 #endif
361
362         mali_session_memory_unlock(session);
363
364         /* Get descriptor mapping for memory. */
365         if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session->descriptor_mapping, descriptor, &md)) {
366                 mali_session_memory_lock(session);
367                 mali_mem_mali_map_free(descriptor);
368                 mali_session_memory_unlock(session);
369
370                 MALI_DEBUG_PRINT_ERROR(("Failed to create descriptor mapping for dma-buf %d\n", fd));
371                 mali_mem_descriptor_destroy(descriptor);
372                 mali_dma_buf_release(mem);
373                 return -EFAULT;
374         }
375
376         /* Return stuff to user space */
377         if (0 != put_user(md, &user_arg->cookie)) {
378                 mali_session_memory_lock(session);
379                 mali_mem_mali_map_free(descriptor);
380                 mali_session_memory_unlock(session);
381
382                 MALI_DEBUG_PRINT_ERROR(("Failed to return descriptor to user space for dma-buf %d\n", fd));
383                 mali_descriptor_mapping_free(session->descriptor_mapping, md);
384                 mali_dma_buf_release(mem);
385                 return -EFAULT;
386         }
387
388         return 0;
389 }
390
391 int mali_release_dma_buf(struct mali_session_data *session, _mali_uk_release_dma_buf_s __user *user_arg)
392 {
393         int ret = 0;
394         _mali_uk_release_dma_buf_s args;
395         mali_mem_allocation *descriptor;
396
397         /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
398         if (0 != copy_from_user(&args, (void __user *)user_arg, sizeof(_mali_uk_release_dma_buf_s))) {
399                 return -EFAULT;
400         }
401
402         MALI_DEBUG_PRINT(3, ("Mali DMA-buf: release descriptor cookie %ld\n", args.cookie));
403
404         mali_session_memory_lock(session);
405
406         descriptor = mali_descriptor_mapping_free(session->descriptor_mapping, (u32)args.cookie);
407
408         if (NULL != descriptor) {
409                 MALI_DEBUG_PRINT(3, ("Mali DMA-buf: Releasing dma-buf at mali address %x\n", descriptor->mali_mapping.addr));
410
411                 mali_mem_mali_map_free(descriptor);
412
413                 mali_dma_buf_release(descriptor->dma_buf.attachment);
414
415                 mali_mem_descriptor_destroy(descriptor);
416         } else {
417                 MALI_DEBUG_PRINT_ERROR(("Invalid memory descriptor %ld used to release dma-buf\n", args.cookie));
418                 ret = -EINVAL;
419         }
420
421         mali_session_memory_unlock(session);
422
423         /* Return the error that _mali_ukk_map_external_ump_mem produced */
424         return ret;
425 }
426
427 int mali_dma_buf_get_size(struct mali_session_data *session, _mali_uk_dma_buf_get_size_s __user *user_arg)
428 {
429         _mali_uk_dma_buf_get_size_s args;
430         int fd;
431         struct dma_buf *buf;
432
433         /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
434         if (0 != copy_from_user(&args, (void __user *)user_arg, sizeof(_mali_uk_dma_buf_get_size_s))) {
435                 return -EFAULT;
436         }
437
438         /* Do DMA-BUF stuff */
439         fd = args.mem_fd;
440
441         buf = dma_buf_get(fd);
442         if (IS_ERR_OR_NULL(buf)) {
443                 MALI_DEBUG_PRINT_ERROR(("Failed to get dma-buf from fd: %d\n", fd));
444                 return PTR_RET(buf);
445         }
446
447         if (0 != put_user(buf->size, &user_arg->size)) {
448                 dma_buf_put(buf);
449                 return -EFAULT;
450         }
451
452         dma_buf_put(buf);
453
454         return 0;
455 }