2 * Copyright (C) 2012-2014 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>
23 #include "mali_kernel_common.h"
24 #include "mali_session.h"
25 #include "mali_kernel_linux.h"
27 #include "mali_memory.h"
28 #include "mali_memory_dma_buf.h"
30 #include "mali_pp_job.h"
32 static void mali_dma_buf_unmap(struct mali_dma_buf_attachment *mem);
34 struct mali_dma_buf_attachment {
36 struct dma_buf_attachment *attachment;
38 struct mali_session_data *session;
40 struct mutex map_lock;
42 wait_queue_head_t wait_queue;
45 static void mali_dma_buf_release(struct mali_dma_buf_attachment *mem)
47 MALI_DEBUG_PRINT(3, ("Mali DMA-buf: release attachment %p\n", mem));
49 MALI_DEBUG_ASSERT_POINTER(mem);
50 MALI_DEBUG_ASSERT_POINTER(mem->attachment);
51 MALI_DEBUG_ASSERT_POINTER(mem->buf);
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);
58 /* Wait for buffer to become unmapped */
59 wait_event(mem->wait_queue, !mem->is_mapped);
60 MALI_DEBUG_ASSERT(!mem->is_mapped);
62 dma_buf_detach(mem->buf, mem->attachment);
63 dma_buf_put(mem->buf);
68 void mali_mem_dma_buf_release(mali_mem_allocation *descriptor)
70 struct mali_dma_buf_attachment *mem = descriptor->dma_buf.attachment;
72 mali_dma_buf_release(mem);
76 * Map DMA buf attachment \a mem into \a session at virtual address \a virt.
78 static int mali_dma_buf_map(struct mali_dma_buf_attachment *mem, struct mali_session_data *session, u32 virt, u32 flags)
80 struct mali_page_directory *pagedir;
81 struct scatterlist *sg;
84 MALI_DEBUG_ASSERT_POINTER(mem);
85 MALI_DEBUG_ASSERT_POINTER(session);
86 MALI_DEBUG_ASSERT(mem->session == session);
88 mutex_lock(&mem->map_lock);
92 MALI_DEBUG_PRINT(5, ("Mali DMA-buf: map attachment %p, new map_ref = %d\n", mem, mem->map_ref));
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);
98 pagedir = mali_session_get_page_directory(session);
99 MALI_DEBUG_ASSERT_POINTER(pagedir);
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"));
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);
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));
115 mali_mmu_pagedir_update(pagedir, virt, phys, size, MALI_MMU_FLAGS_DEFAULT);
120 if (flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) {
122 MALI_DEBUG_PRINT(7, ("Mapping in extra guard page\n"));
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);
128 mem->is_mapped = MALI_TRUE;
129 mutex_unlock(&mem->map_lock);
131 /* Wake up any thread waiting for buffer to become mapped */
132 wake_up_all(&mem->wait_queue);
134 MALI_DEBUG_ASSERT(mem->is_mapped);
135 mutex_unlock(&mem->map_lock);
141 static void mali_dma_buf_unmap(struct mali_dma_buf_attachment *mem)
143 MALI_DEBUG_ASSERT_POINTER(mem);
144 MALI_DEBUG_ASSERT_POINTER(mem->attachment);
145 MALI_DEBUG_ASSERT_POINTER(mem->buf);
147 mutex_lock(&mem->map_lock);
151 MALI_DEBUG_PRINT(5, ("Mali DMA-buf: unmap attachment %p, new map_ref = %d\n", mem, mem->map_ref));
153 if (0 == mem->map_ref) {
154 dma_buf_unmap_attachment(mem->attachment, mem->sgt, DMA_BIDIRECTIONAL);
156 mem->is_mapped = MALI_FALSE;
159 mutex_unlock(&mem->map_lock);
161 /* Wake up any thread waiting for buffer to become unmapped */
162 wake_up_all(&mem->wait_queue);
165 #if !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
166 int mali_dma_buf_map_job(struct mali_pp_job *job)
168 mali_mem_allocation *descriptor;
169 struct mali_dma_buf_attachment *mem;
170 _mali_osk_errcode_t err;
173 u32 num_memory_cookies;
174 struct mali_session_data *session;
176 MALI_DEBUG_ASSERT_POINTER(job);
178 num_memory_cookies = mali_pp_job_num_memory_cookies(job);
180 session = mali_pp_job_get_session(job);
182 MALI_DEBUG_ASSERT_POINTER(session);
184 mali_session_memory_lock(session);
186 for (i = 0; i < num_memory_cookies; i++) {
187 u32 cookie = mali_pp_job_get_memory_cookie(job, i);
190 /* 0 is not a valid cookie */
191 MALI_DEBUG_ASSERT(NULL ==
192 mali_pp_job_get_dma_buf(job, i));
196 MALI_DEBUG_ASSERT(0 < cookie);
198 err = mali_descriptor_mapping_get(
199 mali_pp_job_get_session(job)->descriptor_mapping,
200 cookie, (void **)&descriptor);
202 if (_MALI_OSK_ERR_OK != err) {
203 MALI_DEBUG_PRINT_ERROR(("Mali DMA-buf: Failed to get descriptor for cookie %d\n", cookie));
205 MALI_DEBUG_ASSERT(NULL ==
206 mali_pp_job_get_dma_buf(job, i));
210 if (MALI_MEM_DMA_BUF != descriptor->type) {
212 MALI_DEBUG_ASSERT(NULL ==
213 mali_pp_job_get_dma_buf(job, i));
217 mem = descriptor->dma_buf.attachment;
219 MALI_DEBUG_ASSERT_POINTER(mem);
220 MALI_DEBUG_ASSERT(mem->session == mali_pp_job_get_session(job));
222 err = mali_dma_buf_map(mem, mem->session, descriptor->mali_mapping.addr, descriptor->flags);
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));
227 MALI_DEBUG_ASSERT(NULL ==
228 mali_pp_job_get_dma_buf(job, i));
232 /* Add mem to list of DMA-bufs mapped for this job */
233 mali_pp_job_set_dma_buf(job, i, mem);
236 mali_session_memory_unlock(session);
241 void mali_dma_buf_unmap_job(struct mali_pp_job *job)
244 u32 num_dma_bufs = mali_pp_job_num_dma_bufs(job);
246 for (i = 0; i < num_dma_bufs; i++) {
247 struct mali_dma_buf_attachment *mem;
249 mem = mali_pp_job_get_dma_buf(job, i);
251 mali_dma_buf_unmap(mem);
252 mali_pp_job_set_dma_buf(job, i, NULL);
256 #endif /* !CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH */
258 int mali_attach_dma_buf(struct mali_session_data *session, _mali_uk_attach_dma_buf_s __user *user_arg)
261 struct mali_dma_buf_attachment *mem;
262 _mali_uk_attach_dma_buf_s args;
263 mali_mem_allocation *descriptor;
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))) {
272 if (args.mali_address & ~PAGE_MASK) {
273 MALI_DEBUG_PRINT_ERROR(("Requested address (0x%08x) is not page aligned\n", args.mali_address));
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));
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));
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"));
297 mem = _mali_osk_calloc(1, sizeof(struct mali_dma_buf_attachment));
299 MALI_DEBUG_PRINT_ERROR(("Failed to allocate dma-buf tracing struct\n"));
305 mem->session = session;
307 mutex_init(&mem->map_lock);
308 init_waitqueue_head(&mem->wait_queue);
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);
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);
326 descriptor->size = args.size;
327 descriptor->mali_mapping.addr = args.mali_address;
329 descriptor->dma_buf.attachment = mem;
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;
336 mali_session_memory_lock(session);
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);
347 #if defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
348 /* Map memory into session's Mali virtual address space. */
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);
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);
362 mali_session_memory_unlock(session);
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);
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);
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);
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);
391 int mali_release_dma_buf(struct mali_session_data *session, _mali_uk_release_dma_buf_s __user *user_arg)
394 _mali_uk_release_dma_buf_s args;
395 mali_mem_allocation *descriptor;
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))) {
402 MALI_DEBUG_PRINT(3, ("Mali DMA-buf: release descriptor cookie %ld\n", args.cookie));
404 mali_session_memory_lock(session);
406 descriptor = mali_descriptor_mapping_free(session->descriptor_mapping, (u32)args.cookie);
408 if (NULL != descriptor) {
409 MALI_DEBUG_PRINT(3, ("Mali DMA-buf: Releasing dma-buf at mali address %x\n", descriptor->mali_mapping.addr));
411 mali_mem_mali_map_free(descriptor);
413 mali_dma_buf_release(descriptor->dma_buf.attachment);
415 mali_mem_descriptor_destroy(descriptor);
417 MALI_DEBUG_PRINT_ERROR(("Invalid memory descriptor %ld used to release dma-buf\n", args.cookie));
421 mali_session_memory_unlock(session);
423 /* Return the error that _mali_ukk_map_external_ump_mem produced */
427 int mali_dma_buf_get_size(struct mali_session_data *session, _mali_uk_dma_buf_get_size_s __user *user_arg)
429 _mali_uk_dma_buf_get_size_s args;
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))) {
438 /* Do DMA-BUF stuff */
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));
447 if (0 != put_user(buf->size, &user_arg->size)) {