1b8e80941Smrg/*
2b8e80941Smrg * © Copyright 2019 Collabora, Ltd.
3b8e80941Smrg * Copyright 2019 Alyssa Rosenzweig
4b8e80941Smrg *
5b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
7b8e80941Smrg * to deal in the Software without restriction, including without limitation
8b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
10b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
11b8e80941Smrg *
12b8e80941Smrg * The above copyright notice and this permission notice (including the next
13b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
14b8e80941Smrg * Software.
15b8e80941Smrg *
16b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21b8e80941Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22b8e80941Smrg * SOFTWARE.
23b8e80941Smrg *
24b8e80941Smrg */
25b8e80941Smrg
26b8e80941Smrg#include <fcntl.h>
27b8e80941Smrg#include <xf86drm.h>
28b8e80941Smrg
29b8e80941Smrg#include "drm-uapi/panfrost_drm.h"
30b8e80941Smrg
31b8e80941Smrg#include "util/u_memory.h"
32b8e80941Smrg#include "util/os_time.h"
33b8e80941Smrg#include "os/os_mman.h"
34b8e80941Smrg
35b8e80941Smrg#include "pan_screen.h"
36b8e80941Smrg#include "pan_resource.h"
37b8e80941Smrg#include "pan_context.h"
38b8e80941Smrg#include "pan_drm.h"
39b8e80941Smrg#include "pan_trace.h"
40b8e80941Smrg
41b8e80941Smrgstruct panfrost_drm {
42b8e80941Smrg	struct panfrost_driver base;
43b8e80941Smrg	int fd;
44b8e80941Smrg};
45b8e80941Smrg
46b8e80941Smrgstatic void
47b8e80941Smrgpanfrost_drm_allocate_slab(struct panfrost_screen *screen,
48b8e80941Smrg		           struct panfrost_memory *mem,
49b8e80941Smrg		           size_t pages,
50b8e80941Smrg		           bool same_va,
51b8e80941Smrg		           int extra_flags,
52b8e80941Smrg		           int commit_count,
53b8e80941Smrg		           int extent)
54b8e80941Smrg{
55b8e80941Smrg	struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
56b8e80941Smrg	struct drm_panfrost_create_bo create_bo = {
57b8e80941Smrg		        .size = pages * 4096,
58b8e80941Smrg		        .flags = 0,  // TODO figure out proper flags..
59b8e80941Smrg	};
60b8e80941Smrg	struct drm_panfrost_mmap_bo mmap_bo = {0,};
61b8e80941Smrg	int ret;
62b8e80941Smrg
63b8e80941Smrg	// TODO cache allocations
64b8e80941Smrg	// TODO properly handle errors
65b8e80941Smrg	// TODO take into account extra_flags
66b8e80941Smrg
67b8e80941Smrg	ret = drmIoctl(drm->fd, DRM_IOCTL_PANFROST_CREATE_BO, &create_bo);
68b8e80941Smrg	if (ret) {
69b8e80941Smrg                fprintf(stderr, "DRM_IOCTL_PANFROST_CREATE_BO failed: %d\n", ret);
70b8e80941Smrg		assert(0);
71b8e80941Smrg	}
72b8e80941Smrg
73b8e80941Smrg	mem->gpu = create_bo.offset;
74b8e80941Smrg	mem->gem_handle = create_bo.handle;
75b8e80941Smrg        mem->stack_bottom = 0;
76b8e80941Smrg        mem->size = create_bo.size;
77b8e80941Smrg
78b8e80941Smrg	// TODO map and unmap on demand?
79b8e80941Smrg	mmap_bo.handle = create_bo.handle;
80b8e80941Smrg	ret = drmIoctl(drm->fd, DRM_IOCTL_PANFROST_MMAP_BO, &mmap_bo);
81b8e80941Smrg	if (ret) {
82b8e80941Smrg                fprintf(stderr, "DRM_IOCTL_PANFROST_MMAP_BO failed: %d\n", ret);
83b8e80941Smrg		assert(0);
84b8e80941Smrg	}
85b8e80941Smrg
86b8e80941Smrg        mem->cpu = os_mmap(NULL, mem->size, PROT_READ | PROT_WRITE, MAP_SHARED,
87b8e80941Smrg                       drm->fd, mmap_bo.offset);
88b8e80941Smrg        if (mem->cpu == MAP_FAILED) {
89b8e80941Smrg                fprintf(stderr, "mmap failed: %p\n", mem->cpu);
90b8e80941Smrg		assert(0);
91b8e80941Smrg	}
92b8e80941Smrg
93b8e80941Smrg        /* Record the mmap if we're tracing */
94b8e80941Smrg        if (!(extra_flags & PAN_ALLOCATE_GROWABLE))
95b8e80941Smrg                pantrace_mmap(mem->gpu, mem->cpu, mem->size, NULL);
96b8e80941Smrg}
97b8e80941Smrg
98b8e80941Smrgstatic void
99b8e80941Smrgpanfrost_drm_free_slab(struct panfrost_screen *screen, struct panfrost_memory *mem)
100b8e80941Smrg{
101b8e80941Smrg	struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
102b8e80941Smrg	struct drm_gem_close gem_close = {
103b8e80941Smrg		.handle = mem->gem_handle,
104b8e80941Smrg	};
105b8e80941Smrg	int ret;
106b8e80941Smrg
107b8e80941Smrg        if (os_munmap((void *) (uintptr_t) mem->cpu, mem->size)) {
108b8e80941Smrg                perror("munmap");
109b8e80941Smrg                abort();
110b8e80941Smrg        }
111b8e80941Smrg
112b8e80941Smrg	mem->cpu = NULL;
113b8e80941Smrg
114b8e80941Smrg	ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
115b8e80941Smrg	if (ret) {
116b8e80941Smrg                fprintf(stderr, "DRM_IOCTL_GEM_CLOSE failed: %d\n", ret);
117b8e80941Smrg		assert(0);
118b8e80941Smrg	}
119b8e80941Smrg
120b8e80941Smrg	mem->gem_handle = -1;
121b8e80941Smrg}
122b8e80941Smrg
123b8e80941Smrgstatic struct panfrost_bo *
124b8e80941Smrgpanfrost_drm_import_bo(struct panfrost_screen *screen, struct winsys_handle *whandle)
125b8e80941Smrg{
126b8e80941Smrg	struct panfrost_bo *bo = CALLOC_STRUCT(panfrost_bo);
127b8e80941Smrg	struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
128b8e80941Smrg        struct drm_panfrost_get_bo_offset get_bo_offset = {0,};
129b8e80941Smrg	struct drm_panfrost_mmap_bo mmap_bo = {0,};
130b8e80941Smrg        int ret;
131b8e80941Smrg        unsigned gem_handle;
132b8e80941Smrg
133b8e80941Smrg	ret = drmPrimeFDToHandle(drm->fd, whandle->handle, &gem_handle);
134b8e80941Smrg	assert(!ret);
135b8e80941Smrg
136b8e80941Smrg	get_bo_offset.handle = gem_handle;
137b8e80941Smrg        ret = drmIoctl(drm->fd, DRM_IOCTL_PANFROST_GET_BO_OFFSET, &get_bo_offset);
138b8e80941Smrg        assert(!ret);
139b8e80941Smrg
140b8e80941Smrg	bo->gem_handle = gem_handle;
141b8e80941Smrg        bo->gpu = (mali_ptr) get_bo_offset.offset;
142b8e80941Smrg        pipe_reference_init(&bo->reference, 1);
143b8e80941Smrg
144b8e80941Smrg	// TODO map and unmap on demand?
145b8e80941Smrg	mmap_bo.handle = gem_handle;
146b8e80941Smrg	ret = drmIoctl(drm->fd, DRM_IOCTL_PANFROST_MMAP_BO, &mmap_bo);
147b8e80941Smrg	if (ret) {
148b8e80941Smrg                fprintf(stderr, "DRM_IOCTL_PANFROST_MMAP_BO failed: %d\n", ret);
149b8e80941Smrg		assert(0);
150b8e80941Smrg	}
151b8e80941Smrg
152b8e80941Smrg        bo->size = lseek(whandle->handle, 0, SEEK_END);
153b8e80941Smrg        assert(bo->size > 0);
154b8e80941Smrg        bo->cpu = os_mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
155b8e80941Smrg                       drm->fd, mmap_bo.offset);
156b8e80941Smrg        if (bo->cpu == MAP_FAILED) {
157b8e80941Smrg                fprintf(stderr, "mmap failed: %p\n", bo->cpu);
158b8e80941Smrg		assert(0);
159b8e80941Smrg	}
160b8e80941Smrg
161b8e80941Smrg        /* Record the mmap if we're tracing */
162b8e80941Smrg        pantrace_mmap(bo->gpu, bo->cpu, bo->size, NULL);
163b8e80941Smrg
164b8e80941Smrg        return bo;
165b8e80941Smrg}
166b8e80941Smrg
167b8e80941Smrgstatic int
168b8e80941Smrgpanfrost_drm_export_bo(struct panfrost_screen *screen, int gem_handle, unsigned int stride, struct winsys_handle *whandle)
169b8e80941Smrg{
170b8e80941Smrg	struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
171b8e80941Smrg        struct drm_prime_handle args = {
172b8e80941Smrg                .handle = gem_handle,
173b8e80941Smrg                .flags = DRM_CLOEXEC,
174b8e80941Smrg        };
175b8e80941Smrg
176b8e80941Smrg        int ret = drmIoctl(drm->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
177b8e80941Smrg        if (ret == -1)
178b8e80941Smrg                return FALSE;
179b8e80941Smrg
180b8e80941Smrg        whandle->handle = args.fd;
181b8e80941Smrg        whandle->stride = stride;
182b8e80941Smrg
183b8e80941Smrg        return TRUE;
184b8e80941Smrg}
185b8e80941Smrg
186b8e80941Smrgstatic void
187b8e80941Smrgpanfrost_drm_free_imported_bo(struct panfrost_screen *screen, struct panfrost_bo *bo)
188b8e80941Smrg{
189b8e80941Smrg	struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
190b8e80941Smrg	struct drm_gem_close gem_close = {
191b8e80941Smrg		.handle = bo->gem_handle,
192b8e80941Smrg	};
193b8e80941Smrg	int ret;
194b8e80941Smrg
195b8e80941Smrg	ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
196b8e80941Smrg	if (ret) {
197b8e80941Smrg                fprintf(stderr, "DRM_IOCTL_GEM_CLOSE failed: %d\n", ret);
198b8e80941Smrg		assert(0);
199b8e80941Smrg	}
200b8e80941Smrg
201b8e80941Smrg	bo->gem_handle = -1;
202b8e80941Smrg	bo->gpu = (mali_ptr)NULL;
203b8e80941Smrg}
204b8e80941Smrg
205b8e80941Smrgstatic int
206b8e80941Smrgpanfrost_drm_submit_job(struct panfrost_context *ctx, u64 job_desc, int reqs, struct pipe_surface *surf)
207b8e80941Smrg{
208b8e80941Smrg        struct pipe_context *gallium = (struct pipe_context *) ctx;
209b8e80941Smrg        struct panfrost_screen *screen = pan_screen(gallium->screen);
210b8e80941Smrg	struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
211b8e80941Smrg        struct drm_panfrost_submit submit = {0,};
212b8e80941Smrg        int bo_handles[7];
213b8e80941Smrg
214b8e80941Smrg        submit.in_syncs = (u64) (uintptr_t) &ctx->out_sync;
215b8e80941Smrg        submit.in_sync_count = 1;
216b8e80941Smrg
217b8e80941Smrg        submit.out_sync = ctx->out_sync;
218b8e80941Smrg
219b8e80941Smrg	submit.jc = job_desc;
220b8e80941Smrg	submit.requirements = reqs;
221b8e80941Smrg
222b8e80941Smrg	if (surf) {
223b8e80941Smrg		struct panfrost_resource *res = pan_resource(surf->texture);
224b8e80941Smrg		assert(res->bo->gem_handle > 0);
225b8e80941Smrg		bo_handles[submit.bo_handle_count++] = res->bo->gem_handle;
226b8e80941Smrg
227b8e80941Smrg		if (res->bo->checksum_slab.gem_handle)
228b8e80941Smrg			bo_handles[submit.bo_handle_count++] = res->bo->checksum_slab.gem_handle;
229b8e80941Smrg	}
230b8e80941Smrg
231b8e80941Smrg	/* TODO: Add here the transient pools */
232b8e80941Smrg        /* TODO: Add here the BOs listed in the panfrost_job */
233b8e80941Smrg	bo_handles[submit.bo_handle_count++] = ctx->shaders.gem_handle;
234b8e80941Smrg	bo_handles[submit.bo_handle_count++] = ctx->scratchpad.gem_handle;
235b8e80941Smrg	bo_handles[submit.bo_handle_count++] = ctx->tiler_heap.gem_handle;
236b8e80941Smrg	bo_handles[submit.bo_handle_count++] = ctx->varying_mem.gem_handle;
237b8e80941Smrg	bo_handles[submit.bo_handle_count++] = ctx->misc_0.gem_handle;
238b8e80941Smrg	submit.bo_handles = (u64) (uintptr_t) bo_handles;
239b8e80941Smrg
240b8e80941Smrg        /* Dump memory _before_ submitting so we're not corrupted with actual GPU results */
241b8e80941Smrg        pantrace_dump_memory();
242b8e80941Smrg
243b8e80941Smrg	if (drmIoctl(drm->fd, DRM_IOCTL_PANFROST_SUBMIT, &submit)) {
244b8e80941Smrg	        fprintf(stderr, "Error submitting: %m\n");
245b8e80941Smrg	        return errno;
246b8e80941Smrg	}
247b8e80941Smrg
248b8e80941Smrg        /* Trace the job if we're doing that and do a memory dump. We may
249b8e80941Smrg         * want to adjust this logic once we're ready to trace FBOs */
250b8e80941Smrg        pantrace_submit_job(submit.jc, submit.requirements, FALSE);
251b8e80941Smrg
252b8e80941Smrg	return 0;
253b8e80941Smrg}
254b8e80941Smrg
255b8e80941Smrgstatic int
256b8e80941Smrgpanfrost_drm_submit_vs_fs_job(struct panfrost_context *ctx, bool has_draws, bool is_scanout)
257b8e80941Smrg{
258b8e80941Smrg        struct pipe_surface *surf = ctx->pipe_framebuffer.cbufs[0];
259b8e80941Smrg	int ret;
260b8e80941Smrg
261b8e80941Smrg        if (has_draws) {
262b8e80941Smrg		ret = panfrost_drm_submit_job(ctx, ctx->set_value_job, 0, NULL);
263b8e80941Smrg		assert(!ret);
264b8e80941Smrg	}
265b8e80941Smrg
266b8e80941Smrg	ret = panfrost_drm_submit_job(ctx, panfrost_fragment_job(ctx), PANFROST_JD_REQ_FS, surf);
267b8e80941Smrg
268b8e80941Smrg        return ret;
269b8e80941Smrg}
270b8e80941Smrg
271b8e80941Smrgstatic struct panfrost_fence *
272b8e80941Smrgpanfrost_fence_create(struct panfrost_context *ctx)
273b8e80941Smrg{
274b8e80941Smrg        struct pipe_context *gallium = (struct pipe_context *) ctx;
275b8e80941Smrg        struct panfrost_screen *screen = pan_screen(gallium->screen);
276b8e80941Smrg	struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
277b8e80941Smrg        struct panfrost_fence *f = calloc(1, sizeof(*f));
278b8e80941Smrg        if (!f)
279b8e80941Smrg                return NULL;
280b8e80941Smrg
281b8e80941Smrg        /* Snapshot the last Panfrost's rendering's out fence.  We'd rather have
282b8e80941Smrg         * another syncobj instead of a sync file, but this is all we get.
283b8e80941Smrg         * (HandleToFD/FDToHandle just gives you another syncobj ID for the
284b8e80941Smrg         * same syncobj).
285b8e80941Smrg         */
286b8e80941Smrg        drmSyncobjExportSyncFile(drm->fd, ctx->out_sync, &f->fd);
287b8e80941Smrg        if (f->fd == -1) {
288b8e80941Smrg                fprintf(stderr, "export failed\n");
289b8e80941Smrg                free(f);
290b8e80941Smrg                return NULL;
291b8e80941Smrg        }
292b8e80941Smrg
293b8e80941Smrg        pipe_reference_init(&f->reference, 1);
294b8e80941Smrg
295b8e80941Smrg        return f;
296b8e80941Smrg}
297b8e80941Smrg
298b8e80941Smrgstatic void
299b8e80941Smrgpanfrost_drm_force_flush_fragment(struct panfrost_context *ctx,
300b8e80941Smrg				  struct pipe_fence_handle **fence)
301b8e80941Smrg{
302b8e80941Smrg        struct pipe_context *gallium = (struct pipe_context *) ctx;
303b8e80941Smrg        struct panfrost_screen *screen = pan_screen(gallium->screen);
304b8e80941Smrg        struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
305b8e80941Smrg
306b8e80941Smrg        if (!screen->last_fragment_flushed) {
307b8e80941Smrg		drmSyncobjWait(drm->fd, &ctx->out_sync, 1, INT64_MAX, 0, NULL);
308b8e80941Smrg                screen->last_fragment_flushed = true;
309b8e80941Smrg
310b8e80941Smrg                /* The job finished up, so we're safe to clean it up now */
311b8e80941Smrg                panfrost_free_job(ctx, screen->last_job);
312b8e80941Smrg	}
313b8e80941Smrg
314b8e80941Smrg        if (fence) {
315b8e80941Smrg                struct panfrost_fence *f = panfrost_fence_create(ctx);
316b8e80941Smrg                gallium->screen->fence_reference(gallium->screen, fence, NULL);
317b8e80941Smrg                *fence = (struct pipe_fence_handle *)f;
318b8e80941Smrg        }
319b8e80941Smrg}
320b8e80941Smrg
321b8e80941Smrgstatic void
322b8e80941Smrgpanfrost_drm_enable_counters(struct panfrost_screen *screen)
323b8e80941Smrg{
324b8e80941Smrg	fprintf(stderr, "unimplemented: %s\n", __func__);
325b8e80941Smrg}
326b8e80941Smrg
327b8e80941Smrgstatic void
328b8e80941Smrgpanfrost_drm_dump_counters(struct panfrost_screen *screen)
329b8e80941Smrg{
330b8e80941Smrg	fprintf(stderr, "unimplemented: %s\n", __func__);
331b8e80941Smrg}
332b8e80941Smrg
333b8e80941Smrgstatic unsigned
334b8e80941Smrgpanfrost_drm_query_gpu_version(struct panfrost_screen *screen)
335b8e80941Smrg{
336b8e80941Smrg	struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
337b8e80941Smrg        struct drm_panfrost_get_param get_param = {0,};
338b8e80941Smrg        int ret;
339b8e80941Smrg
340b8e80941Smrg	get_param.param = DRM_PANFROST_PARAM_GPU_ID;
341b8e80941Smrg        ret = drmIoctl(drm->fd, DRM_IOCTL_PANFROST_GET_PARAM, &get_param);
342b8e80941Smrg        assert(!ret);
343b8e80941Smrg
344b8e80941Smrg	return get_param.value;
345b8e80941Smrg}
346b8e80941Smrg
347b8e80941Smrgstatic int
348b8e80941Smrgpanfrost_drm_init_context(struct panfrost_context *ctx)
349b8e80941Smrg{
350b8e80941Smrg        struct pipe_context *gallium = (struct pipe_context *) ctx;
351b8e80941Smrg        struct panfrost_screen *screen = pan_screen(gallium->screen);
352b8e80941Smrg	struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
353b8e80941Smrg
354b8e80941Smrg        return drmSyncobjCreate(drm->fd, DRM_SYNCOBJ_CREATE_SIGNALED,
355b8e80941Smrg                                &ctx->out_sync);
356b8e80941Smrg}
357b8e80941Smrg
358b8e80941Smrgstatic void
359b8e80941Smrgpanfrost_drm_fence_reference(struct pipe_screen *screen,
360b8e80941Smrg                         struct pipe_fence_handle **ptr,
361b8e80941Smrg                         struct pipe_fence_handle *fence)
362b8e80941Smrg{
363b8e80941Smrg        struct panfrost_fence **p = (struct panfrost_fence **)ptr;
364b8e80941Smrg        struct panfrost_fence *f = (struct panfrost_fence *)fence;
365b8e80941Smrg        struct panfrost_fence *old = *p;
366b8e80941Smrg
367b8e80941Smrg        if (pipe_reference(&(*p)->reference, &f->reference)) {
368b8e80941Smrg                close(old->fd);
369b8e80941Smrg                free(old);
370b8e80941Smrg        }
371b8e80941Smrg        *p = f;
372b8e80941Smrg}
373b8e80941Smrg
374b8e80941Smrgstatic boolean
375b8e80941Smrgpanfrost_drm_fence_finish(struct pipe_screen *pscreen,
376b8e80941Smrg                      struct pipe_context *ctx,
377b8e80941Smrg                      struct pipe_fence_handle *fence,
378b8e80941Smrg                      uint64_t timeout)
379b8e80941Smrg{
380b8e80941Smrg        struct panfrost_screen *screen = pan_screen(pscreen);
381b8e80941Smrg	struct panfrost_drm *drm = (struct panfrost_drm *)screen->driver;
382b8e80941Smrg        struct panfrost_fence *f = (struct panfrost_fence *)fence;
383b8e80941Smrg        int ret;
384b8e80941Smrg
385b8e80941Smrg        unsigned syncobj;
386b8e80941Smrg        ret = drmSyncobjCreate(drm->fd, 0, &syncobj);
387b8e80941Smrg        if (ret) {
388b8e80941Smrg                fprintf(stderr, "Failed to create syncobj to wait on: %m\n");
389b8e80941Smrg                return false;
390b8e80941Smrg        }
391b8e80941Smrg
392b8e80941Smrg        drmSyncobjImportSyncFile(drm->fd, syncobj, f->fd);
393b8e80941Smrg        if (ret) {
394b8e80941Smrg                fprintf(stderr, "Failed to import fence to syncobj: %m\n");
395b8e80941Smrg                return false;
396b8e80941Smrg        }
397b8e80941Smrg
398b8e80941Smrg        uint64_t abs_timeout = os_time_get_absolute_timeout(timeout);
399b8e80941Smrg        if (abs_timeout == OS_TIMEOUT_INFINITE)
400b8e80941Smrg                abs_timeout = INT64_MAX;
401b8e80941Smrg
402b8e80941Smrg        ret = drmSyncobjWait(drm->fd, &syncobj, 1, abs_timeout, 0, NULL);
403b8e80941Smrg
404b8e80941Smrg        drmSyncobjDestroy(drm->fd, syncobj);
405b8e80941Smrg
406b8e80941Smrg        return ret >= 0;
407b8e80941Smrg}
408b8e80941Smrg
409b8e80941Smrgstruct panfrost_driver *
410b8e80941Smrgpanfrost_create_drm_driver(int fd)
411b8e80941Smrg{
412b8e80941Smrg	struct panfrost_drm *driver = CALLOC_STRUCT(panfrost_drm);
413b8e80941Smrg
414b8e80941Smrg	driver->fd = fd;
415b8e80941Smrg
416b8e80941Smrg	driver->base.import_bo = panfrost_drm_import_bo;
417b8e80941Smrg	driver->base.export_bo = panfrost_drm_export_bo;
418b8e80941Smrg	driver->base.free_imported_bo = panfrost_drm_free_imported_bo;
419b8e80941Smrg	driver->base.submit_vs_fs_job = panfrost_drm_submit_vs_fs_job;
420b8e80941Smrg	driver->base.force_flush_fragment = panfrost_drm_force_flush_fragment;
421b8e80941Smrg	driver->base.allocate_slab = panfrost_drm_allocate_slab;
422b8e80941Smrg	driver->base.free_slab = panfrost_drm_free_slab;
423b8e80941Smrg	driver->base.enable_counters = panfrost_drm_enable_counters;
424b8e80941Smrg	driver->base.query_gpu_version = panfrost_drm_query_gpu_version;
425b8e80941Smrg	driver->base.init_context = panfrost_drm_init_context;
426b8e80941Smrg	driver->base.fence_reference = panfrost_drm_fence_reference;
427b8e80941Smrg	driver->base.fence_finish = panfrost_drm_fence_finish;
428b8e80941Smrg	driver->base.dump_counters = panfrost_drm_dump_counters;
429b8e80941Smrg
430b8e80941Smrg        return &driver->base;
431b8e80941Smrg}
432