Commit | Line | Data |
---|---|---|
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 | 35 | static 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 | 123 | static 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) | |
150 | int 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 | ||
201 | void 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 | 244 | int 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) |
330 | Failed_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); | |
337 | failed_dma_attach: | |
338 | _mali_osk_free(dma_mem); | |
339 | failed_alloc_mem: | |
340 | dma_buf_put(buf); | |
341 | return _MALI_OSK_ERR_FAULT; | |
6fa3eb70 S |
342 | } |
343 | ||
02af6beb | 344 | void 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 | } |