2 * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
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.
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.
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>
26 #include "mali_kernel_common.h"
27 #include "mali_session.h"
28 #include "mali_kernel_linux.h"
30 #include "mali_memory.h"
31 #include "mali_memory_dma_buf.h"
33 #include "mali_pp_job.h"
35 static void mali_dma_buf_unmap(struct mali_dma_buf_attachment *mem);
37 struct mali_dma_buf_attachment {
39 struct dma_buf_attachment *attachment;
41 struct mali_session_data *session;
43 struct mutex map_lock;
45 wait_queue_head_t wait_queue;
48 static void mali_dma_buf_release(struct mali_dma_buf_attachment *mem)
50 MALI_DEBUG_PRINT(3, ("Mali DMA-buf: release attachment %p\n", mem));
52 MALI_DEBUG_ASSERT_POINTER(mem);
53 MALI_DEBUG_ASSERT_POINTER(mem->attachment);
54 MALI_DEBUG_ASSERT_POINTER(mem->buf);
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);
61 /* Wait for buffer to become unmapped */
62 wait_event(mem->wait_queue, !mem->is_mapped);
63 MALI_DEBUG_ASSERT(!mem->is_mapped);
65 dma_buf_detach(mem->buf, mem->attachment);
66 dma_buf_put(mem->buf);
71 void mali_mem_dma_buf_release(mali_mem_allocation *descriptor)
73 struct mali_dma_buf_attachment *mem = descriptor->dma_buf.attachment;
75 mali_dma_buf_release(mem);
79 * Map DMA buf attachment \a mem into \a session at virtual address \a virt.
81 static int mali_dma_buf_map(struct mali_dma_buf_attachment *mem, struct mali_session_data *session, u32 virt, u32 flags)
83 struct mali_page_directory *pagedir;
84 struct scatterlist *sg;
87 MALI_DEBUG_ASSERT_POINTER(mem);
88 MALI_DEBUG_ASSERT_POINTER(session);
89 MALI_DEBUG_ASSERT(mem->session == session);
91 mutex_lock(&mem->map_lock);
95 MALI_DEBUG_PRINT(5, ("Mali DMA-buf: map attachment %p, new map_ref = %d\n", mem, mem->map_ref));
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);
101 pagedir = mali_session_get_page_directory(session);
102 MALI_DEBUG_ASSERT_POINTER(pagedir);
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"));
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);
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);
119 /* sg must be page aligned. */
120 MALI_DEBUG_ASSERT(0 == size % MALI_MMU_PAGE_SIZE);
122 mali_mmu_pagedir_update(pagedir, virt, phys, size, MALI_MMU_FLAGS_DEFAULT);
127 if (flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) {
129 MALI_DEBUG_PRINT(7, ("Mapping in extra guard page\n"));
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);
135 mem->is_mapped = MALI_TRUE;
136 mutex_unlock(&mem->map_lock);
138 /* Wake up any thread waiting for buffer to become mapped */
139 wake_up_all(&mem->wait_queue);
141 MALI_DEBUG_ASSERT(mem->is_mapped);
142 mutex_unlock(&mem->map_lock);
148 static void mali_dma_buf_unmap(struct mali_dma_buf_attachment *mem)
150 MALI_DEBUG_ASSERT_POINTER(mem);
151 MALI_DEBUG_ASSERT_POINTER(mem->attachment);
152 MALI_DEBUG_ASSERT_POINTER(mem->buf);
154 mutex_lock(&mem->map_lock);
158 MALI_DEBUG_PRINT(5, ("Mali DMA-buf: unmap attachment %p, new map_ref = %d\n", mem, mem->map_ref));
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);
166 mem->is_mapped = MALI_FALSE;
169 mutex_unlock(&mem->map_lock);
171 /* Wake up any thread waiting for buffer to become unmapped */
172 wake_up_all(&mem->wait_queue);
175 #if !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
176 int mali_dma_buf_map_job(struct mali_pp_job *job)
178 mali_mem_allocation *descriptor;
179 struct mali_dma_buf_attachment *mem;
180 _mali_osk_errcode_t err;
184 _mali_osk_mutex_wait(job->session->memory_lock);
186 for (i = 0; i < job->num_memory_cookies; i++) {
187 int cookie = job->memory_cookies[i];
190 /* 0 is not a valid cookie */
191 MALI_DEBUG_ASSERT(NULL == job->dma_bufs[i]);
195 MALI_DEBUG_ASSERT(0 < cookie);
197 err = mali_descriptor_mapping_get(job->session->descriptor_mapping,
198 cookie, (void**)&descriptor);
200 if (_MALI_OSK_ERR_OK != err) {
201 MALI_DEBUG_PRINT_ERROR(("Mali DMA-buf: Failed to get descriptor for cookie %d\n", cookie));
203 MALI_DEBUG_ASSERT(NULL == job->dma_bufs[i]);
207 if (MALI_MEM_DMA_BUF != descriptor->type) {
209 MALI_DEBUG_ASSERT(NULL == job->dma_bufs[i]);
213 mem = descriptor->dma_buf.attachment;
215 MALI_DEBUG_ASSERT_POINTER(mem);
216 MALI_DEBUG_ASSERT(mem->session == job->session);
218 err = mali_dma_buf_map(mem, mem->session, descriptor->mali_mapping.addr, descriptor->flags);
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));
223 MALI_DEBUG_ASSERT(NULL == job->dma_bufs[i]);
227 /* Add mem to list of DMA-bufs mapped for this job */
228 job->dma_bufs[i] = mem;
231 _mali_osk_mutex_signal(job->session->memory_lock);
236 void mali_dma_buf_unmap_job(struct mali_pp_job *job)
239 for (i = 0; i < job->num_dma_bufs; i++) {
240 if (NULL == job->dma_bufs[i]) continue;
242 mali_dma_buf_unmap(job->dma_bufs[i]);
243 job->dma_bufs[i] = NULL;
246 #endif /* !CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH */
248 int mali_attach_dma_buf(struct mali_session_data *session, _mali_uk_attach_dma_buf_s __user *user_arg)
251 struct mali_dma_buf_attachment *mem;
252 _mali_uk_attach_dma_buf_s args;
253 mali_mem_allocation *descriptor;
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))) {
262 if (args.mali_address & ~PAGE_MASK) {
263 MALI_DEBUG_PRINT_ERROR(("Requested address (0x%08x) is not page aligned\n", args.mali_address));
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));
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));
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"));
287 mem = _mali_osk_calloc(1, sizeof(struct mali_dma_buf_attachment));
289 MALI_DEBUG_PRINT_ERROR(("Failed to allocate dma-buf tracing struct\n"));
295 mem->session = session;
297 mutex_init(&mem->map_lock);
298 init_waitqueue_head(&mem->wait_queue);
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);
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);
316 descriptor->size = args.size;
317 descriptor->mali_mapping.addr = args.mali_address;
319 descriptor->dma_buf.attachment = mem;
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;
326 _mali_osk_mutex_wait(session->memory_lock);
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);
337 #if defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
338 /* Map memory into session's Mali virtual address space. */
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);
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);
352 _mali_osk_mutex_signal(session->memory_lock);
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);
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);
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);
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);
381 int mali_release_dma_buf(struct mali_session_data *session, _mali_uk_release_dma_buf_s __user *user_arg)
384 _mali_uk_release_dma_buf_s args;
385 mali_mem_allocation *descriptor;
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)) ) {
392 MALI_DEBUG_PRINT(3, ("Mali DMA-buf: release descriptor cookie %d\n", args.cookie));
394 _mali_osk_mutex_wait(session->memory_lock);
396 descriptor = mali_descriptor_mapping_free(session->descriptor_mapping, args.cookie);
398 if (NULL != descriptor) {
399 MALI_DEBUG_PRINT(3, ("Mali DMA-buf: Releasing dma-buf at mali address %x\n", descriptor->mali_mapping.addr));
401 mali_mem_mali_map_free(descriptor);
403 mali_dma_buf_release(descriptor->dma_buf.attachment);
405 mali_mem_descriptor_destroy(descriptor);
407 MALI_DEBUG_PRINT_ERROR(("Invalid memory descriptor %d used to release dma-buf\n", args.cookie));
411 _mali_osk_mutex_signal(session->memory_lock);
413 /* Return the error that _mali_ukk_map_external_ump_mem produced */
417 int mali_dma_buf_get_size(struct mali_session_data *session, _mali_uk_dma_buf_get_size_s __user *user_arg)
419 _mali_uk_dma_buf_get_size_s args;
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)) ) {
428 /* Do DMA-BUF stuff */
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));
437 if (0 != put_user(buf->size, &user_arg->size)) {