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