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>
8 #include <drm/drm_file.h>
9 #include <drm/drm_syncobj.h>
10 #include <drm/drm_utils.h>
12 #include <drm/lima_drm.h>
18 int lima_gem_create_handle(struct drm_device
*dev
, struct drm_file
*file
,
19 u32 size
, u32 flags
, u32
*handle
)
23 struct drm_gem_shmem_object
*shmem
;
24 struct drm_gem_object
*obj
;
27 shmem
= drm_gem_shmem_create(dev
, size
);
29 return PTR_ERR(shmem
);
33 /* Mali Utgard GPU can only support 32bit address space */
34 mask
= mapping_gfp_mask(obj
->filp
->f_mapping
);
35 mask
&= ~__GFP_HIGHMEM
;
37 mapping_set_gfp_mask(obj
->filp
->f_mapping
, mask
);
39 sgt
= drm_gem_shmem_get_pages_sgt(obj
);
45 err
= drm_gem_handle_create(file
, obj
, handle
);
48 /* drop reference from allocate - handle holds it now */
49 drm_gem_object_put_unlocked(obj
);
54 static void lima_gem_free_object(struct drm_gem_object
*obj
)
56 struct lima_bo
*bo
= to_lima_bo(obj
);
58 if (!list_empty(&bo
->va
))
59 dev_err(obj
->dev
->dev
, "lima gem free bo still has va\n");
61 drm_gem_shmem_free_object(obj
);
64 static int lima_gem_object_open(struct drm_gem_object
*obj
, struct drm_file
*file
)
66 struct lima_bo
*bo
= to_lima_bo(obj
);
67 struct lima_drm_priv
*priv
= to_lima_drm_priv(file
);
68 struct lima_vm
*vm
= priv
->vm
;
70 return lima_vm_bo_add(vm
, bo
, true);
73 static void lima_gem_object_close(struct drm_gem_object
*obj
, struct drm_file
*file
)
75 struct lima_bo
*bo
= to_lima_bo(obj
);
76 struct lima_drm_priv
*priv
= to_lima_drm_priv(file
);
77 struct lima_vm
*vm
= priv
->vm
;
79 lima_vm_bo_del(vm
, bo
);
82 static const struct drm_gem_object_funcs lima_gem_funcs
= {
83 .free
= lima_gem_free_object
,
84 .open
= lima_gem_object_open
,
85 .close
= lima_gem_object_close
,
86 .print_info
= drm_gem_shmem_print_info
,
87 .pin
= drm_gem_shmem_pin
,
88 .unpin
= drm_gem_shmem_unpin
,
89 .get_sg_table
= drm_gem_shmem_get_sg_table
,
90 .vmap
= drm_gem_shmem_vmap
,
91 .vunmap
= drm_gem_shmem_vunmap
,
92 .mmap
= drm_gem_shmem_mmap
,
95 struct drm_gem_object
*lima_gem_create_object(struct drm_device
*dev
, size_t size
)
99 bo
= kzalloc(sizeof(*bo
), GFP_KERNEL
);
103 mutex_init(&bo
->lock
);
104 INIT_LIST_HEAD(&bo
->va
);
106 bo
->base
.base
.funcs
= &lima_gem_funcs
;
108 return &bo
->base
.base
;
111 int lima_gem_get_info(struct drm_file
*file
, u32 handle
, u32
*va
, u64
*offset
)
113 struct drm_gem_object
*obj
;
115 struct lima_drm_priv
*priv
= to_lima_drm_priv(file
);
116 struct lima_vm
*vm
= priv
->vm
;
118 obj
= drm_gem_object_lookup(file
, handle
);
122 bo
= to_lima_bo(obj
);
124 *va
= lima_vm_get_va(vm
, bo
);
126 *offset
= drm_vma_node_offset_addr(&obj
->vma_node
);
128 drm_gem_object_put_unlocked(obj
);
132 static int lima_gem_sync_bo(struct lima_sched_task
*task
, struct lima_bo
*bo
,
133 bool write
, bool explicit)
138 err
= dma_resv_reserve_shared(lima_bo_resv(bo
), 1);
143 /* explicit sync use user passed dep fence */
147 return drm_gem_fence_array_add_implicit(&task
->deps
, &bo
->base
.base
, write
);
150 static int lima_gem_add_deps(struct drm_file
*file
, struct lima_submit
*submit
)
154 for (i
= 0; i
< ARRAY_SIZE(submit
->in_sync
); i
++) {
155 struct dma_fence
*fence
= NULL
;
157 if (!submit
->in_sync
[i
])
160 err
= drm_syncobj_find_fence(file
, submit
->in_sync
[i
],
165 err
= drm_gem_fence_array_add(&submit
->task
->deps
, fence
);
167 dma_fence_put(fence
);
175 int lima_gem_submit(struct drm_file
*file
, struct lima_submit
*submit
)
178 struct ww_acquire_ctx ctx
;
179 struct lima_drm_priv
*priv
= to_lima_drm_priv(file
);
180 struct lima_vm
*vm
= priv
->vm
;
181 struct drm_syncobj
*out_sync
= NULL
;
182 struct dma_fence
*fence
;
183 struct lima_bo
**bos
= submit
->lbos
;
185 if (submit
->out_sync
) {
186 out_sync
= drm_syncobj_find(file
, submit
->out_sync
);
191 for (i
= 0; i
< submit
->nr_bos
; i
++) {
192 struct drm_gem_object
*obj
;
195 obj
= drm_gem_object_lookup(file
, submit
->bos
[i
].handle
);
201 bo
= to_lima_bo(obj
);
203 /* increase refcnt of gpu va map to prevent unmapped when executing,
204 * will be decreased when task done
206 err
= lima_vm_bo_add(vm
, bo
, false);
208 drm_gem_object_put_unlocked(obj
);
215 err
= drm_gem_lock_reservations((struct drm_gem_object
**)bos
,
216 submit
->nr_bos
, &ctx
);
220 err
= lima_sched_task_init(
221 submit
->task
, submit
->ctx
->context
+ submit
->pipe
,
222 bos
, submit
->nr_bos
, vm
);
226 err
= lima_gem_add_deps(file
, submit
);
230 for (i
= 0; i
< submit
->nr_bos
; i
++) {
231 err
= lima_gem_sync_bo(
232 submit
->task
, bos
[i
],
233 submit
->bos
[i
].flags
& LIMA_SUBMIT_BO_WRITE
,
234 submit
->flags
& LIMA_SUBMIT_FLAG_EXPLICIT_FENCE
);
239 fence
= lima_sched_context_queue_task(
240 submit
->ctx
->context
+ submit
->pipe
, submit
->task
);
242 for (i
= 0; i
< submit
->nr_bos
; i
++) {
243 if (submit
->bos
[i
].flags
& LIMA_SUBMIT_BO_WRITE
)
244 dma_resv_add_excl_fence(lima_bo_resv(bos
[i
]), fence
);
246 dma_resv_add_shared_fence(lima_bo_resv(bos
[i
]), fence
);
249 drm_gem_unlock_reservations((struct drm_gem_object
**)bos
,
250 submit
->nr_bos
, &ctx
);
252 for (i
= 0; i
< submit
->nr_bos
; i
++)
253 drm_gem_object_put_unlocked(&bos
[i
]->base
.base
);
256 drm_syncobj_replace_fence(out_sync
, fence
);
257 drm_syncobj_put(out_sync
);
260 dma_fence_put(fence
);
265 lima_sched_task_fini(submit
->task
);
267 drm_gem_unlock_reservations((struct drm_gem_object
**)bos
,
268 submit
->nr_bos
, &ctx
);
270 for (i
= 0; i
< submit
->nr_bos
; i
++) {
273 lima_vm_bo_del(vm
, bos
[i
]);
274 drm_gem_object_put_unlocked(&bos
[i
]->base
.base
);
277 drm_syncobj_put(out_sync
);
281 int lima_gem_wait(struct drm_file
*file
, u32 handle
, u32 op
, s64 timeout_ns
)
283 bool write
= op
& LIMA_GEM_WAIT_WRITE
;
289 timeout
= drm_timeout_abs_to_jiffies(timeout_ns
);
291 ret
= drm_gem_dma_resv_wait(file
, handle
, write
, timeout
);
293 ret
= timeout
? -ETIMEDOUT
: -EBUSY
;