mali mess
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / gpu / mt8127 / mali / mali / linux / mali_memory_dma_buf.c
CommitLineData
6fa3eb70
S
1/*
2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
02af6beb 4 * (C) COPYRIGHT 2012-2015 ARM Limited
6fa3eb70
S
5 * ALL RIGHTS RESERVED
6 * The entire notice above must be reproduced on all authorised
7 * copies and copies may only be made to the extent permitted
8 * by a licensing agreement from ARM Limited.
9 */
10
02af6beb
S
11#include <linux/fs.h> /* file system operations */
12#include <asm/uaccess.h> /* user space access */
6fa3eb70
S
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"
02af6beb 29#include "mali_memory_virtual.h"
6fa3eb70
S
30#include "mali_pp_job.h"
31
6fa3eb70
S
32/*
33 * Map DMA buf attachment \a mem into \a session at virtual address \a virt.
34 */
02af6beb 35static int mali_dma_buf_map(mali_mem_backend *mem_backend)
6fa3eb70 36{
02af6beb
S
37 mali_mem_allocation *alloc;
38 struct mali_dma_buf_attachment *mem;
39 struct mali_session_data *session;
6fa3eb70 40 struct mali_page_directory *pagedir;
02af6beb 41 _mali_osk_errcode_t err;
6fa3eb70 42 struct scatterlist *sg;
02af6beb 43 u32 virt, flags;
6fa3eb70
S
44 int i;
45
02af6beb
S
46 MALI_DEBUG_ASSERT_POINTER(mem_backend);
47
48 alloc = mem_backend->mali_allocation;
49 MALI_DEBUG_ASSERT_POINTER(alloc);
50
51 mem = mem_backend->dma_buf.attachment;
6fa3eb70 52 MALI_DEBUG_ASSERT_POINTER(mem);
02af6beb
S
53
54 session = alloc->session;
6fa3eb70
S
55 MALI_DEBUG_ASSERT_POINTER(session);
56 MALI_DEBUG_ASSERT(mem->session == session);
57
02af6beb
S
58 virt = alloc->mali_vma_node.vm_node.start;
59 flags = alloc->flags;
6fa3eb70 60
02af6beb 61 mali_session_memory_lock(session);
6fa3eb70
S
62 mem->map_ref++;
63
64 MALI_DEBUG_PRINT(5, ("Mali DMA-buf: map attachment %p, new map_ref = %d\n", mem, mem->map_ref));
65
66 if (1 == mem->map_ref) {
02af6beb 67
6fa3eb70
S
68 /* First reference taken, so we need to map the dma buf */
69 MALI_DEBUG_ASSERT(!mem->is_mapped);
70
6fa3eb70
S
71 mem->sgt = dma_buf_map_attachment(mem->attachment, DMA_BIDIRECTIONAL);
72 if (IS_ERR_OR_NULL(mem->sgt)) {
73 MALI_DEBUG_PRINT_ERROR(("Failed to map dma-buf attachment\n"));
02af6beb
S
74 mem->map_ref--;
75 mali_session_memory_unlock(session);
6fa3eb70
S
76 return -EFAULT;
77 }
78
02af6beb
S
79 err = mali_mem_mali_map_prepare(alloc);
80 if (_MALI_OSK_ERR_OK != err) {
81 MALI_DEBUG_PRINT(1, ("Mapping of DMA memory failed\n"));
82 mem->map_ref--;
83 mali_session_memory_unlock(session);
84 return -ENOMEM;
85 }
86
87 pagedir = mali_session_get_page_directory(session);
88 MALI_DEBUG_ASSERT_POINTER(pagedir);
89
6fa3eb70
S
90 for_each_sg(mem->sgt->sgl, sg, mem->sgt->nents, i) {
91 u32 size = sg_dma_len(sg);
92 dma_addr_t phys = sg_dma_address(sg);
93
94 /* sg must be page aligned. */
95 MALI_DEBUG_ASSERT(0 == size % MALI_MMU_PAGE_SIZE);
02af6beb 96 MALI_DEBUG_ASSERT(0 == (phys & ~(uintptr_t)0xFFFFFFFF));
6fa3eb70
S
97
98 mali_mmu_pagedir_update(pagedir, virt, phys, size, MALI_MMU_FLAGS_DEFAULT);
99
100 virt += size;
101 }
102
103 if (flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) {
104 u32 guard_phys;
105 MALI_DEBUG_PRINT(7, ("Mapping in extra guard page\n"));
106
107 guard_phys = sg_dma_address(mem->sgt->sgl);
108 mali_mmu_pagedir_update(pagedir, virt, guard_phys, MALI_MMU_PAGE_SIZE, MALI_MMU_FLAGS_DEFAULT);
109 }
110
111 mem->is_mapped = MALI_TRUE;
02af6beb 112 mali_session_memory_unlock(session);
6fa3eb70
S
113 /* Wake up any thread waiting for buffer to become mapped */
114 wake_up_all(&mem->wait_queue);
115 } else {
116 MALI_DEBUG_ASSERT(mem->is_mapped);
02af6beb 117 mali_session_memory_unlock(session);
6fa3eb70
S
118 }
119
120 return 0;
121}
122
02af6beb 123static void mali_dma_buf_unmap(mali_mem_allocation *alloc, struct mali_dma_buf_attachment *mem)
6fa3eb70 124{
02af6beb 125 MALI_DEBUG_ASSERT_POINTER(alloc);
6fa3eb70
S
126 MALI_DEBUG_ASSERT_POINTER(mem);
127 MALI_DEBUG_ASSERT_POINTER(mem->attachment);
128 MALI_DEBUG_ASSERT_POINTER(mem->buf);
02af6beb 129 MALI_DEBUG_ASSERT_POINTER(alloc->session);
6fa3eb70 130
02af6beb 131 mali_session_memory_lock(alloc->session);
6fa3eb70
S
132 mem->map_ref--;
133
134 MALI_DEBUG_PRINT(5, ("Mali DMA-buf: unmap attachment %p, new map_ref = %d\n", mem, mem->map_ref));
135
136 if (0 == mem->map_ref) {
137 dma_buf_unmap_attachment(mem->attachment, mem->sgt, DMA_BIDIRECTIONAL);
02af6beb
S
138 if (MALI_TRUE == mem->is_mapped) {
139 mali_mem_mali_map_free(alloc->session, alloc->psize, alloc->mali_vma_node.vm_node.start,
140 alloc->flags);
141 }
6fa3eb70
S
142 mem->is_mapped = MALI_FALSE;
143 }
02af6beb 144 mali_session_memory_unlock(alloc->session);
6fa3eb70
S
145 /* Wake up any thread waiting for buffer to become unmapped */
146 wake_up_all(&mem->wait_queue);
147}
148
149#if !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
150int mali_dma_buf_map_job(struct mali_pp_job *job)
151{
6fa3eb70
S
152 struct mali_dma_buf_attachment *mem;
153 _mali_osk_errcode_t err;
154 int i;
155 int ret = 0;
02af6beb
S
156 u32 num_memory_cookies;
157 struct mali_session_data *session;
158 struct mali_vma_node *mali_vma_node = NULL;
159 mali_mem_allocation *mali_alloc = NULL;
160 mali_mem_backend *mem_bkend = NULL;
6fa3eb70 161
02af6beb 162 MALI_DEBUG_ASSERT_POINTER(job);
6fa3eb70 163
02af6beb 164 num_memory_cookies = mali_pp_job_num_memory_cookies(job);
6fa3eb70 165
02af6beb 166 session = mali_pp_job_get_session(job);
6fa3eb70 167
02af6beb 168 MALI_DEBUG_ASSERT_POINTER(session);
6fa3eb70 169
02af6beb
S
170 for (i = 0; i < num_memory_cookies; i++) {
171 u32 mali_addr = mali_pp_job_get_memory_cookie(job, i);
172 mali_vma_node = mali_vma_offset_search(&session->allocation_mgr, mali_addr, 0);
173 MALI_DEBUG_ASSERT(NULL != mali_vma_node);
174 mali_alloc = container_of(mali_vma_node, struct mali_mem_allocation, mali_vma_node);
175 MALI_DEBUG_ASSERT(NULL != mali_alloc);
176 if (MALI_MEM_DMA_BUF != mali_alloc->type) {
6fa3eb70
S
177 continue;
178 }
179
02af6beb
S
180 /* Get backend memory & Map on CPU */
181 mutex_lock(&mali_idr_mutex);
182 mem_bkend = idr_find(&mali_backend_idr, mali_alloc->backend_handle);
183 mutex_unlock(&mali_idr_mutex);
184 MALI_DEBUG_ASSERT(NULL != mem_bkend);
6fa3eb70 185
02af6beb 186 mem = mem_bkend->dma_buf.attachment;
6fa3eb70
S
187
188 MALI_DEBUG_ASSERT_POINTER(mem);
02af6beb 189 MALI_DEBUG_ASSERT(mem->session == mali_pp_job_get_session(job));
6fa3eb70 190
02af6beb 191 err = mali_dma_buf_map(mem_bkend);
6fa3eb70 192 if (0 != err) {
02af6beb 193 MALI_DEBUG_PRINT_ERROR(("Mali DMA-buf: Failed to map dma-buf for mali address %x\n", mali_addr));
6fa3eb70 194 ret = -EFAULT;
6fa3eb70
S
195 continue;
196 }
6fa3eb70 197 }
6fa3eb70
S
198 return ret;
199}
200
201void mali_dma_buf_unmap_job(struct mali_pp_job *job)
202{
02af6beb 203 struct mali_dma_buf_attachment *mem;
6fa3eb70 204 int i;
02af6beb
S
205 u32 num_memory_cookies;
206 struct mali_session_data *session;
207 struct mali_vma_node *mali_vma_node = NULL;
208 mali_mem_allocation *mali_alloc = NULL;
209 mali_mem_backend *mem_bkend = NULL;
210
211 MALI_DEBUG_ASSERT_POINTER(job);
6fa3eb70 212
02af6beb
S
213 num_memory_cookies = mali_pp_job_num_memory_cookies(job);
214
215 session = mali_pp_job_get_session(job);
216
217 MALI_DEBUG_ASSERT_POINTER(session);
218
219 for (i = 0; i < num_memory_cookies; i++) {
220 u32 mali_addr = mali_pp_job_get_memory_cookie(job, i);
221 mali_vma_node = mali_vma_offset_search(&session->allocation_mgr, mali_addr, 0);
222 MALI_DEBUG_ASSERT(NULL != mali_vma_node);
223 mali_alloc = container_of(mali_vma_node, struct mali_mem_allocation, mali_vma_node);
224 MALI_DEBUG_ASSERT(NULL != mali_alloc);
225 if (MALI_MEM_DMA_BUF != mali_alloc->type) {
226 continue;
227 }
228
229 /* Get backend memory & Map on CPU */
230 mutex_lock(&mali_idr_mutex);
231 mem_bkend = idr_find(&mali_backend_idr, mali_alloc->backend_handle);
232 mutex_unlock(&mali_idr_mutex);
233 MALI_DEBUG_ASSERT(NULL != mem_bkend);
234
235 mem = mem_bkend->dma_buf.attachment;
236
237 MALI_DEBUG_ASSERT_POINTER(mem);
238 MALI_DEBUG_ASSERT(mem->session == mali_pp_job_get_session(job));
239 mali_dma_buf_unmap(mem_bkend->mali_allocation, mem);
6fa3eb70
S
240 }
241}
242#endif /* !CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH */
243
02af6beb 244int mali_dma_buf_get_size(struct mali_session_data *session, _mali_uk_dma_buf_get_size_s __user *user_arg)
6fa3eb70 245{
02af6beb 246 _mali_uk_dma_buf_get_size_s args;
6fa3eb70 247 int fd;
02af6beb 248 struct dma_buf *buf;
6fa3eb70 249
02af6beb
S
250 /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
251 if (0 != copy_from_user(&args, (void __user *)user_arg, sizeof(_mali_uk_dma_buf_get_size_s))) {
6fa3eb70
S
252 return -EFAULT;
253 }
254
02af6beb 255 /* Do DMA-BUF stuff */
6fa3eb70
S
256 fd = args.mem_fd;
257
258 buf = dma_buf_get(fd);
259 if (IS_ERR_OR_NULL(buf)) {
260 MALI_DEBUG_PRINT_ERROR(("Failed to get dma-buf from fd: %d\n", fd));
261 return PTR_RET(buf);
262 }
263
02af6beb 264 if (0 != put_user(buf->size, &user_arg->size)) {
6fa3eb70 265 dma_buf_put(buf);
6fa3eb70
S
266 return -EFAULT;
267 }
268
02af6beb 269 dma_buf_put(buf);
6fa3eb70 270
02af6beb
S
271 return 0;
272}
6fa3eb70 273
02af6beb
S
274_mali_osk_errcode_t mali_mem_bind_dma_buf(mali_mem_allocation *alloc,
275 mali_mem_backend *mem_backend,
276 int fd, u32 flags)
277{
278 struct dma_buf *buf;
279 struct mali_dma_buf_attachment *dma_mem;
280 struct mali_session_data *session = alloc->session;
6fa3eb70 281
02af6beb
S
282 MALI_DEBUG_ASSERT_POINTER(session);
283 MALI_DEBUG_ASSERT_POINTER(mem_backend);
284 MALI_DEBUG_ASSERT_POINTER(alloc);
6fa3eb70 285
02af6beb
S
286 /* get dma buffer */
287 buf = dma_buf_get(fd);
288 if (IS_ERR_OR_NULL(buf)) {
289 return _MALI_OSK_ERR_FAULT;
6fa3eb70
S
290 }
291
02af6beb
S
292 /* Currently, mapping of the full buffer are supported. */
293 if (alloc->psize != buf->size) {
294 goto failed_alloc_mem;
6fa3eb70
S
295 }
296
02af6beb
S
297 dma_mem = _mali_osk_calloc(1, sizeof(struct mali_dma_buf_attachment));
298 if (NULL == dma_mem) {
299 goto failed_alloc_mem;
6fa3eb70
S
300 }
301
02af6beb
S
302 dma_mem->buf = buf;
303 dma_mem->session = session;
304 dma_mem->map_ref = 0;
305 init_waitqueue_head(&dma_mem->wait_queue);
6fa3eb70 306
02af6beb
S
307 dma_mem->attachment = dma_buf_attach(dma_mem->buf, &mali_platform_device->dev);
308 if (NULL == dma_mem->attachment) {
309 goto failed_dma_attach;
6fa3eb70
S
310 }
311
02af6beb 312 mem_backend->dma_buf.attachment = dma_mem;
6fa3eb70 313
02af6beb
S
314 alloc->flags |= MALI_MEM_FLAG_DONT_CPU_MAP;
315 if (flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) {
316 alloc->flags |= MALI_MEM_FLAG_MALI_GUARD_PAGE;
6fa3eb70
S
317 }
318
6fa3eb70 319
02af6beb
S
320#if defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
321 /* Map memory into session's Mali virtual address space. */
322 if (0 != mali_dma_buf_map(mem_backend)) {
323 goto Failed_dma_map;
6fa3eb70 324 }
02af6beb 325#endif
6fa3eb70 326
02af6beb 327 return _MALI_OSK_ERR_OK;
6fa3eb70 328
02af6beb
S
329#if defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
330Failed_dma_map:
331 mali_dma_buf_unmap(alloc, dma_mem);
332#endif
333 /* Wait for buffer to become unmapped */
334 wait_event(dma_mem->wait_queue, !dma_mem->is_mapped);
335 MALI_DEBUG_ASSERT(!dma_mem->is_mapped);
336 dma_buf_detach(dma_mem->buf, dma_mem->attachment);
337failed_dma_attach:
338 _mali_osk_free(dma_mem);
339failed_alloc_mem:
340 dma_buf_put(buf);
341 return _MALI_OSK_ERR_FAULT;
6fa3eb70
S
342}
343
02af6beb 344void mali_mem_unbind_dma_buf(mali_mem_backend *mem_backend)
6fa3eb70 345{
02af6beb
S
346 struct mali_dma_buf_attachment *mem;
347 MALI_DEBUG_ASSERT_POINTER(mem_backend);
348 MALI_DEBUG_ASSERT(MALI_MEM_DMA_BUF == mem_backend->type);
6fa3eb70 349
02af6beb
S
350 mem = mem_backend->dma_buf.attachment;
351 MALI_DEBUG_ASSERT_POINTER(mem);
352 MALI_DEBUG_ASSERT_POINTER(mem->attachment);
353 MALI_DEBUG_ASSERT_POINTER(mem->buf);
354 MALI_DEBUG_PRINT(3, ("Mali DMA-buf: release attachment %p\n", mem));
6fa3eb70 355
02af6beb
S
356#if defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
357 MALI_DEBUG_ASSERT_POINTER(mem_backend->mali_allocation);
358 /* We mapped implicitly on attach, so we need to unmap on release */
359 mali_dma_buf_unmap(mem_backend->mali_allocation, mem);
360#endif
361 /* Wait for buffer to become unmapped */
362 wait_event(mem->wait_queue, !mem->is_mapped);
363 MALI_DEBUG_ASSERT(!mem->is_mapped);
6fa3eb70 364
02af6beb
S
365 dma_buf_detach(mem->buf, mem->attachment);
366 dma_buf_put(mem->buf);
6fa3eb70 367
02af6beb 368 _mali_osk_free(mem);
6fa3eb70 369}