1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */
5 #include <linux/sync_file.h>
6 #include <linux/pagemap.h>
7 #include <linux/shmem_fs.h>
8 #include <linux/dma-mapping.h>
10 #include <drm/drm_file.h>
11 #include <drm/drm_syncobj.h>
12 #include <drm/drm_utils.h>
14 #include <drm/lima_drm.h>
20 int lima_heap_alloc(struct lima_bo
*bo
, struct lima_vm
*vm
)
23 struct address_space
*mapping
= bo
->base
.base
.filp
->f_mapping
;
24 struct device
*dev
= bo
->base
.base
.dev
->dev
;
25 size_t old_size
= bo
->heap_size
;
26 size_t new_size
= bo
->heap_size
? bo
->heap_size
* 2 :
27 (lima_heap_init_nr_pages
<< PAGE_SHIFT
);
31 if (bo
->heap_size
>= bo
->base
.base
.size
)
34 new_size
= min(new_size
, bo
->base
.base
.size
);
36 mutex_lock(&bo
->base
.pages_lock
);
39 pages
= bo
->base
.pages
;
41 pages
= kvmalloc_array(bo
->base
.base
.size
>> PAGE_SHIFT
,
42 sizeof(*pages
), GFP_KERNEL
| __GFP_ZERO
);
44 mutex_unlock(&bo
->base
.pages_lock
);
48 bo
->base
.pages
= pages
;
49 bo
->base
.pages_use_count
= 1;
51 mapping_set_unevictable(mapping
);
54 for (i
= old_size
>> PAGE_SHIFT
; i
< new_size
>> PAGE_SHIFT
; i
++) {
55 struct page
*page
= shmem_read_mapping_page(mapping
, i
);
58 mutex_unlock(&bo
->base
.pages_lock
);
64 mutex_unlock(&bo
->base
.pages_lock
);
66 ret
= sg_alloc_table_from_pages(&sgt
, pages
, i
, 0,
67 new_size
, GFP_KERNEL
);
72 dma_unmap_sgtable(dev
, bo
->base
.sgt
, DMA_BIDIRECTIONAL
, 0);
73 sg_free_table(bo
->base
.sgt
);
75 bo
->base
.sgt
= kmalloc(sizeof(*bo
->base
.sgt
), GFP_KERNEL
);
82 ret
= dma_map_sgtable(dev
, &sgt
, DMA_BIDIRECTIONAL
, 0);
93 ret
= lima_vm_map_bo(vm
, bo
, old_size
>> PAGE_SHIFT
);
98 bo
->heap_size
= new_size
;
102 int lima_gem_create_handle(struct drm_device
*dev
, struct drm_file
*file
,
103 u32 size
, u32 flags
, u32
*handle
)
107 struct drm_gem_shmem_object
*shmem
;
108 struct drm_gem_object
*obj
;
110 bool is_heap
= flags
& LIMA_BO_FLAG_HEAP
;
112 shmem
= drm_gem_shmem_create(dev
, size
);
114 return PTR_ERR(shmem
);
118 /* Mali Utgard GPU can only support 32bit address space */
119 mask
= mapping_gfp_mask(obj
->filp
->f_mapping
);
120 mask
&= ~__GFP_HIGHMEM
;
122 mapping_set_gfp_mask(obj
->filp
->f_mapping
, mask
);
125 bo
= to_lima_bo(obj
);
126 err
= lima_heap_alloc(bo
, NULL
);
130 struct sg_table
*sgt
= drm_gem_shmem_get_pages_sgt(obj
);
138 err
= drm_gem_handle_create(file
, obj
, handle
);
141 /* drop reference from allocate - handle holds it now */
142 drm_gem_object_put(obj
);
147 static void lima_gem_free_object(struct drm_gem_object
*obj
)
149 struct lima_bo
*bo
= to_lima_bo(obj
);
151 if (!list_empty(&bo
->va
))
152 dev_err(obj
->dev
->dev
, "lima gem free bo still has va\n");
154 drm_gem_shmem_free_object(obj
);
157 static int lima_gem_object_open(struct drm_gem_object
*obj
, struct drm_file
*file
)
159 struct lima_bo
*bo
= to_lima_bo(obj
);
160 struct lima_drm_priv
*priv
= to_lima_drm_priv(file
);
161 struct lima_vm
*vm
= priv
->vm
;
163 return lima_vm_bo_add(vm
, bo
, true);
166 static void lima_gem_object_close(struct drm_gem_object
*obj
, struct drm_file
*file
)
168 struct lima_bo
*bo
= to_lima_bo(obj
);
169 struct lima_drm_priv
*priv
= to_lima_drm_priv(file
);
170 struct lima_vm
*vm
= priv
->vm
;
172 lima_vm_bo_del(vm
, bo
);
175 static int lima_gem_pin(struct drm_gem_object
*obj
)
177 struct lima_bo
*bo
= to_lima_bo(obj
);
182 return drm_gem_shmem_pin(obj
);
185 static int lima_gem_vmap(struct drm_gem_object
*obj
, struct dma_buf_map
*map
)
187 struct lima_bo
*bo
= to_lima_bo(obj
);
192 return drm_gem_shmem_vmap(obj
, map
);
195 static int lima_gem_mmap(struct drm_gem_object
*obj
, struct vm_area_struct
*vma
)
197 struct lima_bo
*bo
= to_lima_bo(obj
);
202 return drm_gem_shmem_mmap(obj
, vma
);
205 static const struct drm_gem_object_funcs lima_gem_funcs
= {
206 .free
= lima_gem_free_object
,
207 .open
= lima_gem_object_open
,
208 .close
= lima_gem_object_close
,
209 .print_info
= drm_gem_shmem_print_info
,
211 .unpin
= drm_gem_shmem_unpin
,
212 .get_sg_table
= drm_gem_shmem_get_sg_table
,
213 .vmap
= lima_gem_vmap
,
214 .vunmap
= drm_gem_shmem_vunmap
,
215 .mmap
= lima_gem_mmap
,
218 struct drm_gem_object
*lima_gem_create_object(struct drm_device
*dev
, size_t size
)
222 bo
= kzalloc(sizeof(*bo
), GFP_KERNEL
);
226 mutex_init(&bo
->lock
);
227 INIT_LIST_HEAD(&bo
->va
);
228 bo
->base
.map_wc
= true;
229 bo
->base
.base
.funcs
= &lima_gem_funcs
;
231 return &bo
->base
.base
;
234 int lima_gem_get_info(struct drm_file
*file
, u32 handle
, u32
*va
, u64
*offset
)
236 struct drm_gem_object
*obj
;
238 struct lima_drm_priv
*priv
= to_lima_drm_priv(file
);
239 struct lima_vm
*vm
= priv
->vm
;
241 obj
= drm_gem_object_lookup(file
, handle
);
245 bo
= to_lima_bo(obj
);
247 *va
= lima_vm_get_va(vm
, bo
);
249 *offset
= drm_vma_node_offset_addr(&obj
->vma_node
);
251 drm_gem_object_put(obj
);
255 static int lima_gem_sync_bo(struct lima_sched_task
*task
, struct lima_bo
*bo
,
256 bool write
, bool explicit)
261 err
= dma_resv_reserve_shared(lima_bo_resv(bo
), 1);
266 /* explicit sync use user passed dep fence */
270 return drm_gem_fence_array_add_implicit(&task
->deps
, &bo
->base
.base
, write
);
273 static int lima_gem_add_deps(struct drm_file
*file
, struct lima_submit
*submit
)
277 for (i
= 0; i
< ARRAY_SIZE(submit
->in_sync
); i
++) {
278 struct dma_fence
*fence
= NULL
;
280 if (!submit
->in_sync
[i
])
283 err
= drm_syncobj_find_fence(file
, submit
->in_sync
[i
],
288 err
= drm_gem_fence_array_add(&submit
->task
->deps
, fence
);
290 dma_fence_put(fence
);
298 int lima_gem_submit(struct drm_file
*file
, struct lima_submit
*submit
)
301 struct ww_acquire_ctx ctx
;
302 struct lima_drm_priv
*priv
= to_lima_drm_priv(file
);
303 struct lima_vm
*vm
= priv
->vm
;
304 struct drm_syncobj
*out_sync
= NULL
;
305 struct dma_fence
*fence
;
306 struct lima_bo
**bos
= submit
->lbos
;
308 if (submit
->out_sync
) {
309 out_sync
= drm_syncobj_find(file
, submit
->out_sync
);
314 for (i
= 0; i
< submit
->nr_bos
; i
++) {
315 struct drm_gem_object
*obj
;
318 obj
= drm_gem_object_lookup(file
, submit
->bos
[i
].handle
);
324 bo
= to_lima_bo(obj
);
326 /* increase refcnt of gpu va map to prevent unmapped when executing,
327 * will be decreased when task done
329 err
= lima_vm_bo_add(vm
, bo
, false);
331 drm_gem_object_put(obj
);
338 err
= drm_gem_lock_reservations((struct drm_gem_object
**)bos
,
339 submit
->nr_bos
, &ctx
);
343 err
= lima_sched_task_init(
344 submit
->task
, submit
->ctx
->context
+ submit
->pipe
,
345 bos
, submit
->nr_bos
, vm
);
349 err
= lima_gem_add_deps(file
, submit
);
353 for (i
= 0; i
< submit
->nr_bos
; i
++) {
354 err
= lima_gem_sync_bo(
355 submit
->task
, bos
[i
],
356 submit
->bos
[i
].flags
& LIMA_SUBMIT_BO_WRITE
,
357 submit
->flags
& LIMA_SUBMIT_FLAG_EXPLICIT_FENCE
);
362 fence
= lima_sched_context_queue_task(
363 submit
->ctx
->context
+ submit
->pipe
, submit
->task
);
365 for (i
= 0; i
< submit
->nr_bos
; i
++) {
366 if (submit
->bos
[i
].flags
& LIMA_SUBMIT_BO_WRITE
)
367 dma_resv_add_excl_fence(lima_bo_resv(bos
[i
]), fence
);
369 dma_resv_add_shared_fence(lima_bo_resv(bos
[i
]), fence
);
372 drm_gem_unlock_reservations((struct drm_gem_object
**)bos
,
373 submit
->nr_bos
, &ctx
);
375 for (i
= 0; i
< submit
->nr_bos
; i
++)
376 drm_gem_object_put(&bos
[i
]->base
.base
);
379 drm_syncobj_replace_fence(out_sync
, fence
);
380 drm_syncobj_put(out_sync
);
383 dma_fence_put(fence
);
388 lima_sched_task_fini(submit
->task
);
390 drm_gem_unlock_reservations((struct drm_gem_object
**)bos
,
391 submit
->nr_bos
, &ctx
);
393 for (i
= 0; i
< submit
->nr_bos
; i
++) {
396 lima_vm_bo_del(vm
, bos
[i
]);
397 drm_gem_object_put(&bos
[i
]->base
.base
);
400 drm_syncobj_put(out_sync
);
404 int lima_gem_wait(struct drm_file
*file
, u32 handle
, u32 op
, s64 timeout_ns
)
406 bool write
= op
& LIMA_GEM_WAIT_WRITE
;
412 timeout
= drm_timeout_abs_to_jiffies(timeout_ns
);
414 ret
= drm_gem_dma_resv_wait(file
, handle
, write
, timeout
);
416 ret
= timeout
? -ETIMEDOUT
: -EBUSY
;