]> Git Repo - linux.git/blob - drivers/gpu/drm/panthor/panthor_drv.c
Merge tag 'cxl-for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
[linux.git] / drivers / gpu / drm / panthor / panthor_drv.c
1 // SPDX-License-Identifier: GPL-2.0 or MIT
2 /* Copyright 2018 Marty E. Plummer <[email protected]> */
3 /* Copyright 2019 Linaro, Ltd., Rob Herring <[email protected]> */
4 /* Copyright 2019 Collabora ltd. */
5
6 #include <linux/list.h>
7 #include <linux/module.h>
8 #include <linux/of_platform.h>
9 #include <linux/pagemap.h>
10 #include <linux/platform_device.h>
11 #include <linux/pm_runtime.h>
12
13 #include <drm/drm_debugfs.h>
14 #include <drm/drm_drv.h>
15 #include <drm/drm_exec.h>
16 #include <drm/drm_ioctl.h>
17 #include <drm/drm_syncobj.h>
18 #include <drm/drm_utils.h>
19 #include <drm/gpu_scheduler.h>
20 #include <drm/panthor_drm.h>
21
22 #include "panthor_device.h"
23 #include "panthor_fw.h"
24 #include "panthor_gem.h"
25 #include "panthor_gpu.h"
26 #include "panthor_heap.h"
27 #include "panthor_mmu.h"
28 #include "panthor_regs.h"
29 #include "panthor_sched.h"
30
31 /**
32  * DOC: user <-> kernel object copy helpers.
33  */
34
35 /**
36  * panthor_set_uobj() - Copy kernel object to user object.
37  * @usr_ptr: Users pointer.
38  * @usr_size: Size of the user object.
39  * @min_size: Minimum size for this object.
40  * @kern_size: Size of the kernel object.
41  * @in: Address of the kernel object to copy.
42  *
43  * Helper automating kernel -> user object copies.
44  *
45  * Don't use this function directly, use PANTHOR_UOBJ_SET() instead.
46  *
47  * Return: 0 on success, a negative error code otherwise.
48  */
49 static int
50 panthor_set_uobj(u64 usr_ptr, u32 usr_size, u32 min_size, u32 kern_size, const void *in)
51 {
52         /* User size shouldn't be smaller than the minimal object size. */
53         if (usr_size < min_size)
54                 return -EINVAL;
55
56         if (copy_to_user(u64_to_user_ptr(usr_ptr), in, min_t(u32, usr_size, kern_size)))
57                 return -EFAULT;
58
59         /* When the kernel object is smaller than the user object, we fill the gap with
60          * zeros.
61          */
62         if (usr_size > kern_size &&
63             clear_user(u64_to_user_ptr(usr_ptr + kern_size), usr_size - kern_size)) {
64                 return -EFAULT;
65         }
66
67         return 0;
68 }
69
70 /**
71  * panthor_get_uobj_array() - Copy a user object array into a kernel accessible object array.
72  * @in: The object array to copy.
73  * @min_stride: Minimum array stride.
74  * @obj_size: Kernel object size.
75  *
76  * Helper automating user -> kernel object copies.
77  *
78  * Don't use this function directly, use PANTHOR_UOBJ_GET_ARRAY() instead.
79  *
80  * Return: newly allocated object array or an ERR_PTR on error.
81  */
82 static void *
83 panthor_get_uobj_array(const struct drm_panthor_obj_array *in, u32 min_stride,
84                        u32 obj_size)
85 {
86         int ret = 0;
87         void *out_alloc;
88
89         /* User stride must be at least the minimum object size, otherwise it might
90          * lack useful information.
91          */
92         if (in->stride < min_stride)
93                 return ERR_PTR(-EINVAL);
94
95         if (!in->count)
96                 return NULL;
97
98         out_alloc = kvmalloc_array(in->count, obj_size, GFP_KERNEL);
99         if (!out_alloc)
100                 return ERR_PTR(-ENOMEM);
101
102         if (obj_size == in->stride) {
103                 /* Fast path when user/kernel have the same uAPI header version. */
104                 if (copy_from_user(out_alloc, u64_to_user_ptr(in->array),
105                                    (unsigned long)obj_size * in->count))
106                         ret = -EFAULT;
107         } else {
108                 void __user *in_ptr = u64_to_user_ptr(in->array);
109                 void *out_ptr = out_alloc;
110
111                 /* If the sizes differ, we need to copy elements one by one. */
112                 for (u32 i = 0; i < in->count; i++) {
113                         ret = copy_struct_from_user(out_ptr, obj_size, in_ptr, in->stride);
114                         if (ret)
115                                 break;
116
117                         out_ptr += obj_size;
118                         in_ptr += in->stride;
119                 }
120         }
121
122         if (ret) {
123                 kvfree(out_alloc);
124                 return ERR_PTR(ret);
125         }
126
127         return out_alloc;
128 }
129
130 /**
131  * PANTHOR_UOBJ_MIN_SIZE_INTERNAL() - Get the minimum user object size
132  * @_typename: Object type.
133  * @_last_mandatory_field: Last mandatory field.
134  *
135  * Get the minimum user object size based on the last mandatory field name,
136  * A.K.A, the name of the last field of the structure at the time this
137  * structure was added to the uAPI.
138  *
139  * Don't use directly, use PANTHOR_UOBJ_DECL() instead.
140  */
141 #define PANTHOR_UOBJ_MIN_SIZE_INTERNAL(_typename, _last_mandatory_field) \
142         (offsetof(_typename, _last_mandatory_field) + \
143          sizeof(((_typename *)NULL)->_last_mandatory_field))
144
145 /**
146  * PANTHOR_UOBJ_DECL() - Declare a new uAPI object whose subject to
147  * evolutions.
148  * @_typename: Object type.
149  * @_last_mandatory_field: Last mandatory field.
150  *
151  * Should be used to extend the PANTHOR_UOBJ_MIN_SIZE() list.
152  */
153 #define PANTHOR_UOBJ_DECL(_typename, _last_mandatory_field) \
154         _typename : PANTHOR_UOBJ_MIN_SIZE_INTERNAL(_typename, _last_mandatory_field)
155
156 /**
157  * PANTHOR_UOBJ_MIN_SIZE() - Get the minimum size of a given uAPI object
158  * @_obj_name: Object to get the minimum size of.
159  *
160  * Don't use this macro directly, it's automatically called by
161  * PANTHOR_UOBJ_{SET,GET_ARRAY}().
162  */
163 #define PANTHOR_UOBJ_MIN_SIZE(_obj_name) \
164         _Generic(_obj_name, \
165                  PANTHOR_UOBJ_DECL(struct drm_panthor_gpu_info, tiler_present), \
166                  PANTHOR_UOBJ_DECL(struct drm_panthor_csif_info, pad), \
167                  PANTHOR_UOBJ_DECL(struct drm_panthor_sync_op, timeline_value), \
168                  PANTHOR_UOBJ_DECL(struct drm_panthor_queue_submit, syncs), \
169                  PANTHOR_UOBJ_DECL(struct drm_panthor_queue_create, ringbuf_size), \
170                  PANTHOR_UOBJ_DECL(struct drm_panthor_vm_bind_op, syncs))
171
172 /**
173  * PANTHOR_UOBJ_SET() - Copy a kernel object to a user object.
174  * @_dest_usr_ptr: User pointer to copy to.
175  * @_usr_size: Size of the user object.
176  * @_src_obj: Kernel object to copy (not a pointer).
177  *
178  * Return: 0 on success, a negative error code otherwise.
179  */
180 #define PANTHOR_UOBJ_SET(_dest_usr_ptr, _usr_size, _src_obj) \
181         panthor_set_uobj(_dest_usr_ptr, _usr_size, \
182                          PANTHOR_UOBJ_MIN_SIZE(_src_obj), \
183                          sizeof(_src_obj), &(_src_obj))
184
185 /**
186  * PANTHOR_UOBJ_GET_ARRAY() - Copy a user object array to a kernel accessible
187  * object array.
188  * @_dest_array: Local variable that will hold the newly allocated kernel
189  * object array.
190  * @_uobj_array: The drm_panthor_obj_array object describing the user object
191  * array.
192  *
193  * Return: 0 on success, a negative error code otherwise.
194  */
195 #define PANTHOR_UOBJ_GET_ARRAY(_dest_array, _uobj_array) \
196         ({ \
197                 typeof(_dest_array) _tmp; \
198                 _tmp = panthor_get_uobj_array(_uobj_array, \
199                                               PANTHOR_UOBJ_MIN_SIZE((_dest_array)[0]), \
200                                               sizeof((_dest_array)[0])); \
201                 if (!IS_ERR(_tmp)) \
202                         _dest_array = _tmp; \
203                 PTR_ERR_OR_ZERO(_tmp); \
204         })
205
206 /**
207  * struct panthor_sync_signal - Represent a synchronization object point to attach
208  * our job fence to.
209  *
210  * This structure is here to keep track of fences that are currently bound to
211  * a specific syncobj point.
212  *
213  * At the beginning of a job submission, the fence
214  * is retrieved from the syncobj itself, and can be NULL if no fence was attached
215  * to this point.
216  *
217  * At the end, it points to the fence of the last job that had a
218  * %DRM_PANTHOR_SYNC_OP_SIGNAL on this syncobj.
219  *
220  * With jobs being submitted in batches, the fence might change several times during
221  * the process, allowing one job to wait on a job that's part of the same submission
222  * but appears earlier in the drm_panthor_group_submit::queue_submits array.
223  */
224 struct panthor_sync_signal {
225         /** @node: list_head to track signal ops within a submit operation */
226         struct list_head node;
227
228         /** @handle: The syncobj handle. */
229         u32 handle;
230
231         /**
232          * @point: The syncobj point.
233          *
234          * Zero for regular syncobjs, and non-zero for timeline syncobjs.
235          */
236         u64 point;
237
238         /**
239          * @syncobj: The sync object pointed by @handle.
240          */
241         struct drm_syncobj *syncobj;
242
243         /**
244          * @chain: Chain object used to link the new fence to an existing
245          * timeline syncobj.
246          *
247          * NULL for regular syncobj, non-NULL for timeline syncobjs.
248          */
249         struct dma_fence_chain *chain;
250
251         /**
252          * @fence: The fence to assign to the syncobj or syncobj-point.
253          */
254         struct dma_fence *fence;
255 };
256
257 /**
258  * struct panthor_job_ctx - Job context
259  */
260 struct panthor_job_ctx {
261         /** @job: The job that is about to be submitted to drm_sched. */
262         struct drm_sched_job *job;
263
264         /** @syncops: Array of sync operations. */
265         struct drm_panthor_sync_op *syncops;
266
267         /** @syncop_count: Number of sync operations. */
268         u32 syncop_count;
269 };
270
271 /**
272  * struct panthor_submit_ctx - Submission context
273  *
274  * Anything that's related to a submission (%DRM_IOCTL_PANTHOR_VM_BIND or
275  * %DRM_IOCTL_PANTHOR_GROUP_SUBMIT) is kept here, so we can automate the
276  * initialization and cleanup steps.
277  */
278 struct panthor_submit_ctx {
279         /** @file: DRM file this submission happens on. */
280         struct drm_file *file;
281
282         /**
283          * @signals: List of struct panthor_sync_signal.
284          *
285          * %DRM_PANTHOR_SYNC_OP_SIGNAL operations will be recorded here,
286          * and %DRM_PANTHOR_SYNC_OP_WAIT will first check if an entry
287          * matching the syncobj+point exists before calling
288          * drm_syncobj_find_fence(). This allows us to describe dependencies
289          * existing between jobs that are part of the same batch.
290          */
291         struct list_head signals;
292
293         /** @jobs: Array of jobs. */
294         struct panthor_job_ctx *jobs;
295
296         /** @job_count: Number of entries in the @jobs array. */
297         u32 job_count;
298
299         /** @exec: drm_exec context used to acquire and prepare resv objects. */
300         struct drm_exec exec;
301 };
302
303 #define PANTHOR_SYNC_OP_FLAGS_MASK \
304         (DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_MASK | DRM_PANTHOR_SYNC_OP_SIGNAL)
305
306 static bool sync_op_is_signal(const struct drm_panthor_sync_op *sync_op)
307 {
308         return !!(sync_op->flags & DRM_PANTHOR_SYNC_OP_SIGNAL);
309 }
310
311 static bool sync_op_is_wait(const struct drm_panthor_sync_op *sync_op)
312 {
313         /* Note that DRM_PANTHOR_SYNC_OP_WAIT == 0 */
314         return !(sync_op->flags & DRM_PANTHOR_SYNC_OP_SIGNAL);
315 }
316
317 /**
318  * panthor_check_sync_op() - Check drm_panthor_sync_op fields
319  * @sync_op: The sync operation to check.
320  *
321  * Return: 0 on success, -EINVAL otherwise.
322  */
323 static int
324 panthor_check_sync_op(const struct drm_panthor_sync_op *sync_op)
325 {
326         u8 handle_type;
327
328         if (sync_op->flags & ~PANTHOR_SYNC_OP_FLAGS_MASK)
329                 return -EINVAL;
330
331         handle_type = sync_op->flags & DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_MASK;
332         if (handle_type != DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_SYNCOBJ &&
333             handle_type != DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_TIMELINE_SYNCOBJ)
334                 return -EINVAL;
335
336         if (handle_type == DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_SYNCOBJ &&
337             sync_op->timeline_value != 0)
338                 return -EINVAL;
339
340         return 0;
341 }
342
343 /**
344  * panthor_sync_signal_free() - Release resources and free a panthor_sync_signal object
345  * @sig_sync: Signal object to free.
346  */
347 static void
348 panthor_sync_signal_free(struct panthor_sync_signal *sig_sync)
349 {
350         if (!sig_sync)
351                 return;
352
353         drm_syncobj_put(sig_sync->syncobj);
354         dma_fence_chain_free(sig_sync->chain);
355         dma_fence_put(sig_sync->fence);
356         kfree(sig_sync);
357 }
358
359 /**
360  * panthor_submit_ctx_add_sync_signal() - Add a signal operation to a submit context
361  * @ctx: Context to add the signal operation to.
362  * @handle: Syncobj handle.
363  * @point: Syncobj point.
364  *
365  * Return: 0 on success, otherwise negative error value.
366  */
367 static int
368 panthor_submit_ctx_add_sync_signal(struct panthor_submit_ctx *ctx, u32 handle, u64 point)
369 {
370         struct panthor_sync_signal *sig_sync;
371         struct dma_fence *cur_fence;
372         int ret;
373
374         sig_sync = kzalloc(sizeof(*sig_sync), GFP_KERNEL);
375         if (!sig_sync)
376                 return -ENOMEM;
377
378         sig_sync->handle = handle;
379         sig_sync->point = point;
380
381         if (point > 0) {
382                 sig_sync->chain = dma_fence_chain_alloc();
383                 if (!sig_sync->chain) {
384                         ret = -ENOMEM;
385                         goto err_free_sig_sync;
386                 }
387         }
388
389         sig_sync->syncobj = drm_syncobj_find(ctx->file, handle);
390         if (!sig_sync->syncobj) {
391                 ret = -EINVAL;
392                 goto err_free_sig_sync;
393         }
394
395         /* Retrieve the current fence attached to that point. It's
396          * perfectly fine to get a NULL fence here, it just means there's
397          * no fence attached to that point yet.
398          */
399         if (!drm_syncobj_find_fence(ctx->file, handle, point, 0, &cur_fence))
400                 sig_sync->fence = cur_fence;
401
402         list_add_tail(&sig_sync->node, &ctx->signals);
403
404         return 0;
405
406 err_free_sig_sync:
407         panthor_sync_signal_free(sig_sync);
408         return ret;
409 }
410
411 /**
412  * panthor_submit_ctx_search_sync_signal() - Search an existing signal operation in a
413  * submit context.
414  * @ctx: Context to search the signal operation in.
415  * @handle: Syncobj handle.
416  * @point: Syncobj point.
417  *
418  * Return: A valid panthor_sync_signal object if found, NULL otherwise.
419  */
420 static struct panthor_sync_signal *
421 panthor_submit_ctx_search_sync_signal(struct panthor_submit_ctx *ctx, u32 handle, u64 point)
422 {
423         struct panthor_sync_signal *sig_sync;
424
425         list_for_each_entry(sig_sync, &ctx->signals, node) {
426                 if (handle == sig_sync->handle && point == sig_sync->point)
427                         return sig_sync;
428         }
429
430         return NULL;
431 }
432
433 /**
434  * panthor_submit_ctx_add_job() - Add a job to a submit context
435  * @ctx: Context to search the signal operation in.
436  * @idx: Index of the job in the context.
437  * @job: Job to add.
438  * @syncs: Sync operations provided by userspace.
439  *
440  * Return: 0 on success, a negative error code otherwise.
441  */
442 static int
443 panthor_submit_ctx_add_job(struct panthor_submit_ctx *ctx, u32 idx,
444                            struct drm_sched_job *job,
445                            const struct drm_panthor_obj_array *syncs)
446 {
447         int ret;
448
449         ctx->jobs[idx].job = job;
450
451         ret = PANTHOR_UOBJ_GET_ARRAY(ctx->jobs[idx].syncops, syncs);
452         if (ret)
453                 return ret;
454
455         ctx->jobs[idx].syncop_count = syncs->count;
456         return 0;
457 }
458
459 /**
460  * panthor_submit_ctx_get_sync_signal() - Search signal operation and add one if none was found.
461  * @ctx: Context to search the signal operation in.
462  * @handle: Syncobj handle.
463  * @point: Syncobj point.
464  *
465  * Return: 0 on success, a negative error code otherwise.
466  */
467 static int
468 panthor_submit_ctx_get_sync_signal(struct panthor_submit_ctx *ctx, u32 handle, u64 point)
469 {
470         struct panthor_sync_signal *sig_sync;
471
472         sig_sync = panthor_submit_ctx_search_sync_signal(ctx, handle, point);
473         if (sig_sync)
474                 return 0;
475
476         return panthor_submit_ctx_add_sync_signal(ctx, handle, point);
477 }
478
479 /**
480  * panthor_submit_ctx_update_job_sync_signal_fences() - Update fences
481  * on the signal operations specified by a job.
482  * @ctx: Context to search the signal operation in.
483  * @job_idx: Index of the job to operate on.
484  *
485  * Return: 0 on success, a negative error code otherwise.
486  */
487 static int
488 panthor_submit_ctx_update_job_sync_signal_fences(struct panthor_submit_ctx *ctx,
489                                                  u32 job_idx)
490 {
491         struct panthor_device *ptdev = container_of(ctx->file->minor->dev,
492                                                     struct panthor_device,
493                                                     base);
494         struct dma_fence *done_fence = &ctx->jobs[job_idx].job->s_fence->finished;
495         const struct drm_panthor_sync_op *sync_ops = ctx->jobs[job_idx].syncops;
496         u32 sync_op_count = ctx->jobs[job_idx].syncop_count;
497
498         for (u32 i = 0; i < sync_op_count; i++) {
499                 struct dma_fence *old_fence;
500                 struct panthor_sync_signal *sig_sync;
501
502                 if (!sync_op_is_signal(&sync_ops[i]))
503                         continue;
504
505                 sig_sync = panthor_submit_ctx_search_sync_signal(ctx, sync_ops[i].handle,
506                                                                  sync_ops[i].timeline_value);
507                 if (drm_WARN_ON(&ptdev->base, !sig_sync))
508                         return -EINVAL;
509
510                 old_fence = sig_sync->fence;
511                 sig_sync->fence = dma_fence_get(done_fence);
512                 dma_fence_put(old_fence);
513
514                 if (drm_WARN_ON(&ptdev->base, !sig_sync->fence))
515                         return -EINVAL;
516         }
517
518         return 0;
519 }
520
521 /**
522  * panthor_submit_ctx_collect_job_signal_ops() - Iterate over all job signal operations
523  * and add them to the context.
524  * @ctx: Context to search the signal operation in.
525  * @job_idx: Index of the job to operate on.
526  *
527  * Return: 0 on success, a negative error code otherwise.
528  */
529 static int
530 panthor_submit_ctx_collect_job_signal_ops(struct panthor_submit_ctx *ctx,
531                                           u32 job_idx)
532 {
533         const struct drm_panthor_sync_op *sync_ops = ctx->jobs[job_idx].syncops;
534         u32 sync_op_count = ctx->jobs[job_idx].syncop_count;
535
536         for (u32 i = 0; i < sync_op_count; i++) {
537                 int ret;
538
539                 if (!sync_op_is_signal(&sync_ops[i]))
540                         continue;
541
542                 ret = panthor_check_sync_op(&sync_ops[i]);
543                 if (ret)
544                         return ret;
545
546                 ret = panthor_submit_ctx_get_sync_signal(ctx,
547                                                          sync_ops[i].handle,
548                                                          sync_ops[i].timeline_value);
549                 if (ret)
550                         return ret;
551         }
552
553         return 0;
554 }
555
556 /**
557  * panthor_submit_ctx_push_fences() - Iterate over the signal array, and for each entry, push
558  * the currently assigned fence to the associated syncobj.
559  * @ctx: Context to push fences on.
560  *
561  * This is the last step of a submission procedure, and is done once we know the submission
562  * is effective and job fences are guaranteed to be signaled in finite time.
563  */
564 static void
565 panthor_submit_ctx_push_fences(struct panthor_submit_ctx *ctx)
566 {
567         struct panthor_sync_signal *sig_sync;
568
569         list_for_each_entry(sig_sync, &ctx->signals, node) {
570                 if (sig_sync->chain) {
571                         drm_syncobj_add_point(sig_sync->syncobj, sig_sync->chain,
572                                               sig_sync->fence, sig_sync->point);
573                         sig_sync->chain = NULL;
574                 } else {
575                         drm_syncobj_replace_fence(sig_sync->syncobj, sig_sync->fence);
576                 }
577         }
578 }
579
580 /**
581  * panthor_submit_ctx_add_sync_deps_to_job() - Add sync wait operations as
582  * job dependencies.
583  * @ctx: Submit context.
584  * @job_idx: Index of the job to operate on.
585  *
586  * Return: 0 on success, a negative error code otherwise.
587  */
588 static int
589 panthor_submit_ctx_add_sync_deps_to_job(struct panthor_submit_ctx *ctx,
590                                         u32 job_idx)
591 {
592         struct panthor_device *ptdev = container_of(ctx->file->minor->dev,
593                                                     struct panthor_device,
594                                                     base);
595         const struct drm_panthor_sync_op *sync_ops = ctx->jobs[job_idx].syncops;
596         struct drm_sched_job *job = ctx->jobs[job_idx].job;
597         u32 sync_op_count = ctx->jobs[job_idx].syncop_count;
598         int ret = 0;
599
600         for (u32 i = 0; i < sync_op_count; i++) {
601                 struct panthor_sync_signal *sig_sync;
602                 struct dma_fence *fence;
603
604                 if (!sync_op_is_wait(&sync_ops[i]))
605                         continue;
606
607                 ret = panthor_check_sync_op(&sync_ops[i]);
608                 if (ret)
609                         return ret;
610
611                 sig_sync = panthor_submit_ctx_search_sync_signal(ctx, sync_ops[i].handle,
612                                                                  sync_ops[i].timeline_value);
613                 if (sig_sync) {
614                         if (drm_WARN_ON(&ptdev->base, !sig_sync->fence))
615                                 return -EINVAL;
616
617                         fence = dma_fence_get(sig_sync->fence);
618                 } else {
619                         ret = drm_syncobj_find_fence(ctx->file, sync_ops[i].handle,
620                                                      sync_ops[i].timeline_value,
621                                                      0, &fence);
622                         if (ret)
623                                 return ret;
624                 }
625
626                 ret = drm_sched_job_add_dependency(job, fence);
627                 if (ret)
628                         return ret;
629         }
630
631         return 0;
632 }
633
634 /**
635  * panthor_submit_ctx_collect_jobs_signal_ops() - Collect all signal operations
636  * and add them to the submit context.
637  * @ctx: Submit context.
638  *
639  * Return: 0 on success, a negative error code otherwise.
640  */
641 static int
642 panthor_submit_ctx_collect_jobs_signal_ops(struct panthor_submit_ctx *ctx)
643 {
644         for (u32 i = 0; i < ctx->job_count; i++) {
645                 int ret;
646
647                 ret = panthor_submit_ctx_collect_job_signal_ops(ctx, i);
648                 if (ret)
649                         return ret;
650         }
651
652         return 0;
653 }
654
655 /**
656  * panthor_submit_ctx_add_deps_and_arm_jobs() - Add jobs dependencies and arm jobs
657  * @ctx: Submit context.
658  *
659  * Must be called after the resv preparation has been taken care of.
660  *
661  * Return: 0 on success, a negative error code otherwise.
662  */
663 static int
664 panthor_submit_ctx_add_deps_and_arm_jobs(struct panthor_submit_ctx *ctx)
665 {
666         for (u32 i = 0; i < ctx->job_count; i++) {
667                 int ret;
668
669                 ret = panthor_submit_ctx_add_sync_deps_to_job(ctx, i);
670                 if (ret)
671                         return ret;
672
673                 drm_sched_job_arm(ctx->jobs[i].job);
674
675                 ret = panthor_submit_ctx_update_job_sync_signal_fences(ctx, i);
676                 if (ret)
677                         return ret;
678         }
679
680         return 0;
681 }
682
683 /**
684  * panthor_submit_ctx_push_jobs() - Push jobs to their scheduling entities.
685  * @ctx: Submit context.
686  * @upd_resvs: Callback used to update reservation objects that were previously
687  * preapred.
688  */
689 static void
690 panthor_submit_ctx_push_jobs(struct panthor_submit_ctx *ctx,
691                              void (*upd_resvs)(struct drm_exec *, struct drm_sched_job *))
692 {
693         for (u32 i = 0; i < ctx->job_count; i++) {
694                 upd_resvs(&ctx->exec, ctx->jobs[i].job);
695                 drm_sched_entity_push_job(ctx->jobs[i].job);
696
697                 /* Job is owned by the scheduler now. */
698                 ctx->jobs[i].job = NULL;
699         }
700
701         panthor_submit_ctx_push_fences(ctx);
702 }
703
704 /**
705  * panthor_submit_ctx_init() - Initializes a submission context
706  * @ctx: Submit context to initialize.
707  * @file: drm_file this submission happens on.
708  * @job_count: Number of jobs that will be submitted.
709  *
710  * Return: 0 on success, a negative error code otherwise.
711  */
712 static int panthor_submit_ctx_init(struct panthor_submit_ctx *ctx,
713                                    struct drm_file *file, u32 job_count)
714 {
715         ctx->jobs = kvmalloc_array(job_count, sizeof(*ctx->jobs),
716                                    GFP_KERNEL | __GFP_ZERO);
717         if (!ctx->jobs)
718                 return -ENOMEM;
719
720         ctx->file = file;
721         ctx->job_count = job_count;
722         INIT_LIST_HEAD(&ctx->signals);
723         drm_exec_init(&ctx->exec,
724                       DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES,
725                       0);
726         return 0;
727 }
728
729 /**
730  * panthor_submit_ctx_cleanup() - Cleanup a submission context
731  * @ctx: Submit context to cleanup.
732  * @job_put: Job put callback.
733  */
734 static void panthor_submit_ctx_cleanup(struct panthor_submit_ctx *ctx,
735                                        void (*job_put)(struct drm_sched_job *))
736 {
737         struct panthor_sync_signal *sig_sync, *tmp;
738         unsigned long i;
739
740         drm_exec_fini(&ctx->exec);
741
742         list_for_each_entry_safe(sig_sync, tmp, &ctx->signals, node)
743                 panthor_sync_signal_free(sig_sync);
744
745         for (i = 0; i < ctx->job_count; i++) {
746                 job_put(ctx->jobs[i].job);
747                 kvfree(ctx->jobs[i].syncops);
748         }
749
750         kvfree(ctx->jobs);
751 }
752
753 static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct drm_file *file)
754 {
755         struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base);
756         struct drm_panthor_dev_query *args = data;
757
758         if (!args->pointer) {
759                 switch (args->type) {
760                 case DRM_PANTHOR_DEV_QUERY_GPU_INFO:
761                         args->size = sizeof(ptdev->gpu_info);
762                         return 0;
763
764                 case DRM_PANTHOR_DEV_QUERY_CSIF_INFO:
765                         args->size = sizeof(ptdev->csif_info);
766                         return 0;
767
768                 default:
769                         return -EINVAL;
770                 }
771         }
772
773         switch (args->type) {
774         case DRM_PANTHOR_DEV_QUERY_GPU_INFO:
775                 return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->gpu_info);
776
777         case DRM_PANTHOR_DEV_QUERY_CSIF_INFO:
778                 return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->csif_info);
779
780         default:
781                 return -EINVAL;
782         }
783 }
784
785 #define PANTHOR_VM_CREATE_FLAGS                 0
786
787 static int panthor_ioctl_vm_create(struct drm_device *ddev, void *data,
788                                    struct drm_file *file)
789 {
790         struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base);
791         struct panthor_file *pfile = file->driver_priv;
792         struct drm_panthor_vm_create *args = data;
793         int cookie, ret;
794
795         if (!drm_dev_enter(ddev, &cookie))
796                 return -ENODEV;
797
798         ret = panthor_vm_pool_create_vm(ptdev, pfile->vms,  args);
799         if (ret >= 0) {
800                 args->id = ret;
801                 ret = 0;
802         }
803
804         drm_dev_exit(cookie);
805         return ret;
806 }
807
808 static int panthor_ioctl_vm_destroy(struct drm_device *ddev, void *data,
809                                     struct drm_file *file)
810 {
811         struct panthor_file *pfile = file->driver_priv;
812         struct drm_panthor_vm_destroy *args = data;
813
814         if (args->pad)
815                 return -EINVAL;
816
817         return panthor_vm_pool_destroy_vm(pfile->vms, args->id);
818 }
819
820 #define PANTHOR_BO_FLAGS                DRM_PANTHOR_BO_NO_MMAP
821
822 static int panthor_ioctl_bo_create(struct drm_device *ddev, void *data,
823                                    struct drm_file *file)
824 {
825         struct panthor_file *pfile = file->driver_priv;
826         struct drm_panthor_bo_create *args = data;
827         struct panthor_vm *vm = NULL;
828         int cookie, ret;
829
830         if (!drm_dev_enter(ddev, &cookie))
831                 return -ENODEV;
832
833         if (!args->size || args->pad ||
834             (args->flags & ~PANTHOR_BO_FLAGS)) {
835                 ret = -EINVAL;
836                 goto out_dev_exit;
837         }
838
839         if (args->exclusive_vm_id) {
840                 vm = panthor_vm_pool_get_vm(pfile->vms, args->exclusive_vm_id);
841                 if (!vm) {
842                         ret = -EINVAL;
843                         goto out_dev_exit;
844                 }
845         }
846
847         ret = panthor_gem_create_with_handle(file, ddev, vm, &args->size,
848                                              args->flags, &args->handle);
849
850         panthor_vm_put(vm);
851
852 out_dev_exit:
853         drm_dev_exit(cookie);
854         return ret;
855 }
856
857 static int panthor_ioctl_bo_mmap_offset(struct drm_device *ddev, void *data,
858                                         struct drm_file *file)
859 {
860         struct drm_panthor_bo_mmap_offset *args = data;
861         struct drm_gem_object *obj;
862         int ret;
863
864         if (args->pad)
865                 return -EINVAL;
866
867         obj = drm_gem_object_lookup(file, args->handle);
868         if (!obj)
869                 return -ENOENT;
870
871         ret = drm_gem_create_mmap_offset(obj);
872         if (ret)
873                 goto out;
874
875         args->offset = drm_vma_node_offset_addr(&obj->vma_node);
876
877 out:
878         drm_gem_object_put(obj);
879         return ret;
880 }
881
882 static int panthor_ioctl_group_submit(struct drm_device *ddev, void *data,
883                                       struct drm_file *file)
884 {
885         struct panthor_file *pfile = file->driver_priv;
886         struct drm_panthor_group_submit *args = data;
887         struct drm_panthor_queue_submit *jobs_args;
888         struct panthor_submit_ctx ctx;
889         int ret = 0, cookie;
890
891         if (args->pad)
892                 return -EINVAL;
893
894         if (!drm_dev_enter(ddev, &cookie))
895                 return -ENODEV;
896
897         ret = PANTHOR_UOBJ_GET_ARRAY(jobs_args, &args->queue_submits);
898         if (ret)
899                 goto out_dev_exit;
900
901         ret = panthor_submit_ctx_init(&ctx, file, args->queue_submits.count);
902         if (ret)
903                 goto out_free_jobs_args;
904
905         /* Create jobs and attach sync operations */
906         for (u32 i = 0; i < args->queue_submits.count; i++) {
907                 const struct drm_panthor_queue_submit *qsubmit = &jobs_args[i];
908                 struct drm_sched_job *job;
909
910                 job = panthor_job_create(pfile, args->group_handle, qsubmit);
911                 if (IS_ERR(job)) {
912                         ret = PTR_ERR(job);
913                         goto out_cleanup_submit_ctx;
914                 }
915
916                 ret = panthor_submit_ctx_add_job(&ctx, i, job, &qsubmit->syncs);
917                 if (ret)
918                         goto out_cleanup_submit_ctx;
919         }
920
921         /*
922          * Collect signal operations on all jobs, such that each job can pick
923          * from it for its dependencies and update the fence to signal when the
924          * job is submitted.
925          */
926         ret = panthor_submit_ctx_collect_jobs_signal_ops(&ctx);
927         if (ret)
928                 goto out_cleanup_submit_ctx;
929
930         /*
931          * We acquire/prepare revs on all jobs before proceeding with the
932          * dependency registration.
933          *
934          * This is solving two problems:
935          * 1. drm_sched_job_arm() and drm_sched_entity_push_job() must be
936          *    protected by a lock to make sure no concurrent access to the same
937          *    entity get interleaved, which would mess up with the fence seqno
938          *    ordering. Luckily, one of the resv being acquired is the VM resv,
939          *    and a scheduling entity is only bound to a single VM. As soon as
940          *    we acquire the VM resv, we should be safe.
941          * 2. Jobs might depend on fences that were issued by previous jobs in
942          *    the same batch, so we can't add dependencies on all jobs before
943          *    arming previous jobs and registering the fence to the signal
944          *    array, otherwise we might miss dependencies, or point to an
945          *    outdated fence.
946          */
947         if (args->queue_submits.count > 0) {
948                 /* All jobs target the same group, so they also point to the same VM. */
949                 struct panthor_vm *vm = panthor_job_vm(ctx.jobs[0].job);
950
951                 drm_exec_until_all_locked(&ctx.exec) {
952                         ret = panthor_vm_prepare_mapped_bos_resvs(&ctx.exec, vm,
953                                                                   args->queue_submits.count);
954                 }
955
956                 if (ret)
957                         goto out_cleanup_submit_ctx;
958         }
959
960         /*
961          * Now that resvs are locked/prepared, we can iterate over each job to
962          * add the dependencies, arm the job fence, register the job fence to
963          * the signal array.
964          */
965         ret = panthor_submit_ctx_add_deps_and_arm_jobs(&ctx);
966         if (ret)
967                 goto out_cleanup_submit_ctx;
968
969         /* Nothing can fail after that point, so we can make our job fences
970          * visible to the outside world. Push jobs and set the job fences to
971          * the resv slots we reserved.  This also pushes the fences to the
972          * syncobjs that are part of the signal array.
973          */
974         panthor_submit_ctx_push_jobs(&ctx, panthor_job_update_resvs);
975
976 out_cleanup_submit_ctx:
977         panthor_submit_ctx_cleanup(&ctx, panthor_job_put);
978
979 out_free_jobs_args:
980         kvfree(jobs_args);
981
982 out_dev_exit:
983         drm_dev_exit(cookie);
984         return ret;
985 }
986
987 static int panthor_ioctl_group_destroy(struct drm_device *ddev, void *data,
988                                        struct drm_file *file)
989 {
990         struct panthor_file *pfile = file->driver_priv;
991         struct drm_panthor_group_destroy *args = data;
992
993         if (args->pad)
994                 return -EINVAL;
995
996         return panthor_group_destroy(pfile, args->group_handle);
997 }
998
999 static int panthor_ioctl_group_create(struct drm_device *ddev, void *data,
1000                                       struct drm_file *file)
1001 {
1002         struct panthor_file *pfile = file->driver_priv;
1003         struct drm_panthor_group_create *args = data;
1004         struct drm_panthor_queue_create *queue_args;
1005         int ret;
1006
1007         if (!args->queues.count)
1008                 return -EINVAL;
1009
1010         ret = PANTHOR_UOBJ_GET_ARRAY(queue_args, &args->queues);
1011         if (ret)
1012                 return ret;
1013
1014         ret = panthor_group_create(pfile, args, queue_args);
1015         if (ret >= 0) {
1016                 args->group_handle = ret;
1017                 ret = 0;
1018         }
1019
1020         kvfree(queue_args);
1021         return ret;
1022 }
1023
1024 static int panthor_ioctl_group_get_state(struct drm_device *ddev, void *data,
1025                                          struct drm_file *file)
1026 {
1027         struct panthor_file *pfile = file->driver_priv;
1028         struct drm_panthor_group_get_state *args = data;
1029
1030         return panthor_group_get_state(pfile, args);
1031 }
1032
1033 static int panthor_ioctl_tiler_heap_create(struct drm_device *ddev, void *data,
1034                                            struct drm_file *file)
1035 {
1036         struct panthor_file *pfile = file->driver_priv;
1037         struct drm_panthor_tiler_heap_create *args = data;
1038         struct panthor_heap_pool *pool;
1039         struct panthor_vm *vm;
1040         int ret;
1041
1042         vm = panthor_vm_pool_get_vm(pfile->vms, args->vm_id);
1043         if (!vm)
1044                 return -EINVAL;
1045
1046         pool = panthor_vm_get_heap_pool(vm, true);
1047         if (IS_ERR(pool)) {
1048                 ret = PTR_ERR(pool);
1049                 goto out_put_vm;
1050         }
1051
1052         ret = panthor_heap_create(pool,
1053                                   args->initial_chunk_count,
1054                                   args->chunk_size,
1055                                   args->max_chunks,
1056                                   args->target_in_flight,
1057                                   &args->tiler_heap_ctx_gpu_va,
1058                                   &args->first_heap_chunk_gpu_va);
1059         if (ret < 0)
1060                 goto out_put_heap_pool;
1061
1062         /* Heap pools are per-VM. We combine the VM and HEAP id to make
1063          * a unique heap handle.
1064          */
1065         args->handle = (args->vm_id << 16) | ret;
1066         ret = 0;
1067
1068 out_put_heap_pool:
1069         panthor_heap_pool_put(pool);
1070
1071 out_put_vm:
1072         panthor_vm_put(vm);
1073         return ret;
1074 }
1075
1076 static int panthor_ioctl_tiler_heap_destroy(struct drm_device *ddev, void *data,
1077                                             struct drm_file *file)
1078 {
1079         struct panthor_file *pfile = file->driver_priv;
1080         struct drm_panthor_tiler_heap_destroy *args = data;
1081         struct panthor_heap_pool *pool;
1082         struct panthor_vm *vm;
1083         int ret;
1084
1085         if (args->pad)
1086                 return -EINVAL;
1087
1088         vm = panthor_vm_pool_get_vm(pfile->vms, args->handle >> 16);
1089         if (!vm)
1090                 return -EINVAL;
1091
1092         pool = panthor_vm_get_heap_pool(vm, false);
1093         if (IS_ERR(pool)) {
1094                 ret = PTR_ERR(pool);
1095                 goto out_put_vm;
1096         }
1097
1098         ret = panthor_heap_destroy(pool, args->handle & GENMASK(15, 0));
1099         panthor_heap_pool_put(pool);
1100
1101 out_put_vm:
1102         panthor_vm_put(vm);
1103         return ret;
1104 }
1105
1106 static int panthor_ioctl_vm_bind_async(struct drm_device *ddev,
1107                                        struct drm_panthor_vm_bind *args,
1108                                        struct drm_file *file)
1109 {
1110         struct panthor_file *pfile = file->driver_priv;
1111         struct drm_panthor_vm_bind_op *jobs_args;
1112         struct panthor_submit_ctx ctx;
1113         struct panthor_vm *vm;
1114         int ret = 0;
1115
1116         vm = panthor_vm_pool_get_vm(pfile->vms, args->vm_id);
1117         if (!vm)
1118                 return -EINVAL;
1119
1120         ret = PANTHOR_UOBJ_GET_ARRAY(jobs_args, &args->ops);
1121         if (ret)
1122                 goto out_put_vm;
1123
1124         ret = panthor_submit_ctx_init(&ctx, file, args->ops.count);
1125         if (ret)
1126                 goto out_free_jobs_args;
1127
1128         for (u32 i = 0; i < args->ops.count; i++) {
1129                 struct drm_panthor_vm_bind_op *op = &jobs_args[i];
1130                 struct drm_sched_job *job;
1131
1132                 job = panthor_vm_bind_job_create(file, vm, op);
1133                 if (IS_ERR(job)) {
1134                         ret = PTR_ERR(job);
1135                         goto out_cleanup_submit_ctx;
1136                 }
1137
1138                 ret = panthor_submit_ctx_add_job(&ctx, i, job, &op->syncs);
1139                 if (ret)
1140                         goto out_cleanup_submit_ctx;
1141         }
1142
1143         ret = panthor_submit_ctx_collect_jobs_signal_ops(&ctx);
1144         if (ret)
1145                 goto out_cleanup_submit_ctx;
1146
1147         /* Prepare reservation objects for each VM_BIND job. */
1148         drm_exec_until_all_locked(&ctx.exec) {
1149                 for (u32 i = 0; i < ctx.job_count; i++) {
1150                         ret = panthor_vm_bind_job_prepare_resvs(&ctx.exec, ctx.jobs[i].job);
1151                         drm_exec_retry_on_contention(&ctx.exec);
1152                         if (ret)
1153                                 goto out_cleanup_submit_ctx;
1154                 }
1155         }
1156
1157         ret = panthor_submit_ctx_add_deps_and_arm_jobs(&ctx);
1158         if (ret)
1159                 goto out_cleanup_submit_ctx;
1160
1161         /* Nothing can fail after that point. */
1162         panthor_submit_ctx_push_jobs(&ctx, panthor_vm_bind_job_update_resvs);
1163
1164 out_cleanup_submit_ctx:
1165         panthor_submit_ctx_cleanup(&ctx, panthor_vm_bind_job_put);
1166
1167 out_free_jobs_args:
1168         kvfree(jobs_args);
1169
1170 out_put_vm:
1171         panthor_vm_put(vm);
1172         return ret;
1173 }
1174
1175 static int panthor_ioctl_vm_bind_sync(struct drm_device *ddev,
1176                                       struct drm_panthor_vm_bind *args,
1177                                       struct drm_file *file)
1178 {
1179         struct panthor_file *pfile = file->driver_priv;
1180         struct drm_panthor_vm_bind_op *jobs_args;
1181         struct panthor_vm *vm;
1182         int ret;
1183
1184         vm = panthor_vm_pool_get_vm(pfile->vms, args->vm_id);
1185         if (!vm)
1186                 return -EINVAL;
1187
1188         ret = PANTHOR_UOBJ_GET_ARRAY(jobs_args, &args->ops);
1189         if (ret)
1190                 goto out_put_vm;
1191
1192         for (u32 i = 0; i < args->ops.count; i++) {
1193                 ret = panthor_vm_bind_exec_sync_op(file, vm, &jobs_args[i]);
1194                 if (ret) {
1195                         /* Update ops.count so the user knows where things failed. */
1196                         args->ops.count = i;
1197                         break;
1198                 }
1199         }
1200
1201         kvfree(jobs_args);
1202
1203 out_put_vm:
1204         panthor_vm_put(vm);
1205         return ret;
1206 }
1207
1208 #define PANTHOR_VM_BIND_FLAGS DRM_PANTHOR_VM_BIND_ASYNC
1209
1210 static int panthor_ioctl_vm_bind(struct drm_device *ddev, void *data,
1211                                  struct drm_file *file)
1212 {
1213         struct drm_panthor_vm_bind *args = data;
1214         int cookie, ret;
1215
1216         if (!drm_dev_enter(ddev, &cookie))
1217                 return -ENODEV;
1218
1219         if (args->flags & DRM_PANTHOR_VM_BIND_ASYNC)
1220                 ret = panthor_ioctl_vm_bind_async(ddev, args, file);
1221         else
1222                 ret = panthor_ioctl_vm_bind_sync(ddev, args, file);
1223
1224         drm_dev_exit(cookie);
1225         return ret;
1226 }
1227
1228 static int panthor_ioctl_vm_get_state(struct drm_device *ddev, void *data,
1229                                       struct drm_file *file)
1230 {
1231         struct panthor_file *pfile = file->driver_priv;
1232         struct drm_panthor_vm_get_state *args = data;
1233         struct panthor_vm *vm;
1234
1235         vm = panthor_vm_pool_get_vm(pfile->vms, args->vm_id);
1236         if (!vm)
1237                 return -EINVAL;
1238
1239         if (panthor_vm_is_unusable(vm))
1240                 args->state = DRM_PANTHOR_VM_STATE_UNUSABLE;
1241         else
1242                 args->state = DRM_PANTHOR_VM_STATE_USABLE;
1243
1244         panthor_vm_put(vm);
1245         return 0;
1246 }
1247
1248 static int
1249 panthor_open(struct drm_device *ddev, struct drm_file *file)
1250 {
1251         struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base);
1252         struct panthor_file *pfile;
1253         int ret;
1254
1255         if (!try_module_get(THIS_MODULE))
1256                 return -EINVAL;
1257
1258         pfile = kzalloc(sizeof(*pfile), GFP_KERNEL);
1259         if (!pfile) {
1260                 ret = -ENOMEM;
1261                 goto err_put_mod;
1262         }
1263
1264         pfile->ptdev = ptdev;
1265
1266         ret = panthor_vm_pool_create(pfile);
1267         if (ret)
1268                 goto err_free_file;
1269
1270         ret = panthor_group_pool_create(pfile);
1271         if (ret)
1272                 goto err_destroy_vm_pool;
1273
1274         file->driver_priv = pfile;
1275         return 0;
1276
1277 err_destroy_vm_pool:
1278         panthor_vm_pool_destroy(pfile);
1279
1280 err_free_file:
1281         kfree(pfile);
1282
1283 err_put_mod:
1284         module_put(THIS_MODULE);
1285         return ret;
1286 }
1287
1288 static void
1289 panthor_postclose(struct drm_device *ddev, struct drm_file *file)
1290 {
1291         struct panthor_file *pfile = file->driver_priv;
1292
1293         panthor_group_pool_destroy(pfile);
1294         panthor_vm_pool_destroy(pfile);
1295
1296         kfree(pfile);
1297         module_put(THIS_MODULE);
1298 }
1299
1300 static const struct drm_ioctl_desc panthor_drm_driver_ioctls[] = {
1301 #define PANTHOR_IOCTL(n, func, flags) \
1302         DRM_IOCTL_DEF_DRV(PANTHOR_##n, panthor_ioctl_##func, flags)
1303
1304         PANTHOR_IOCTL(DEV_QUERY, dev_query, DRM_RENDER_ALLOW),
1305         PANTHOR_IOCTL(VM_CREATE, vm_create, DRM_RENDER_ALLOW),
1306         PANTHOR_IOCTL(VM_DESTROY, vm_destroy, DRM_RENDER_ALLOW),
1307         PANTHOR_IOCTL(VM_BIND, vm_bind, DRM_RENDER_ALLOW),
1308         PANTHOR_IOCTL(VM_GET_STATE, vm_get_state, DRM_RENDER_ALLOW),
1309         PANTHOR_IOCTL(BO_CREATE, bo_create, DRM_RENDER_ALLOW),
1310         PANTHOR_IOCTL(BO_MMAP_OFFSET, bo_mmap_offset, DRM_RENDER_ALLOW),
1311         PANTHOR_IOCTL(GROUP_CREATE, group_create, DRM_RENDER_ALLOW),
1312         PANTHOR_IOCTL(GROUP_DESTROY, group_destroy, DRM_RENDER_ALLOW),
1313         PANTHOR_IOCTL(GROUP_GET_STATE, group_get_state, DRM_RENDER_ALLOW),
1314         PANTHOR_IOCTL(TILER_HEAP_CREATE, tiler_heap_create, DRM_RENDER_ALLOW),
1315         PANTHOR_IOCTL(TILER_HEAP_DESTROY, tiler_heap_destroy, DRM_RENDER_ALLOW),
1316         PANTHOR_IOCTL(GROUP_SUBMIT, group_submit, DRM_RENDER_ALLOW),
1317 };
1318
1319 static int panthor_mmap(struct file *filp, struct vm_area_struct *vma)
1320 {
1321         struct drm_file *file = filp->private_data;
1322         struct panthor_file *pfile = file->driver_priv;
1323         struct panthor_device *ptdev = pfile->ptdev;
1324         u64 offset = (u64)vma->vm_pgoff << PAGE_SHIFT;
1325         int ret, cookie;
1326
1327         if (!drm_dev_enter(file->minor->dev, &cookie))
1328                 return -ENODEV;
1329
1330 #ifdef CONFIG_ARM64
1331         /*
1332          * With 32-bit systems being limited by the 32-bit representation of
1333          * mmap2's pgoffset field, we need to make the MMIO offset arch
1334          * specific. This converts a user MMIO offset into something the kernel
1335          * driver understands.
1336          */
1337         if (test_tsk_thread_flag(current, TIF_32BIT) &&
1338             offset >= DRM_PANTHOR_USER_MMIO_OFFSET_32BIT) {
1339                 offset += DRM_PANTHOR_USER_MMIO_OFFSET_64BIT -
1340                           DRM_PANTHOR_USER_MMIO_OFFSET_32BIT;
1341                 vma->vm_pgoff = offset >> PAGE_SHIFT;
1342         }
1343 #endif
1344
1345         if (offset >= DRM_PANTHOR_USER_MMIO_OFFSET)
1346                 ret = panthor_device_mmap_io(ptdev, vma);
1347         else
1348                 ret = drm_gem_mmap(filp, vma);
1349
1350         drm_dev_exit(cookie);
1351         return ret;
1352 }
1353
1354 static const struct file_operations panthor_drm_driver_fops = {
1355         .open = drm_open,
1356         .release = drm_release,
1357         .unlocked_ioctl = drm_ioctl,
1358         .compat_ioctl = drm_compat_ioctl,
1359         .poll = drm_poll,
1360         .read = drm_read,
1361         .llseek = noop_llseek,
1362         .mmap = panthor_mmap,
1363 };
1364
1365 #ifdef CONFIG_DEBUG_FS
1366 static void panthor_debugfs_init(struct drm_minor *minor)
1367 {
1368         panthor_mmu_debugfs_init(minor);
1369 }
1370 #endif
1371
1372 /*
1373  * PanCSF driver version:
1374  * - 1.0 - initial interface
1375  */
1376 static const struct drm_driver panthor_drm_driver = {
1377         .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ |
1378                            DRIVER_SYNCOBJ_TIMELINE | DRIVER_GEM_GPUVA,
1379         .open = panthor_open,
1380         .postclose = panthor_postclose,
1381         .ioctls = panthor_drm_driver_ioctls,
1382         .num_ioctls = ARRAY_SIZE(panthor_drm_driver_ioctls),
1383         .fops = &panthor_drm_driver_fops,
1384         .name = "panthor",
1385         .desc = "Panthor DRM driver",
1386         .date = "20230801",
1387         .major = 1,
1388         .minor = 0,
1389
1390         .gem_create_object = panthor_gem_create_object,
1391         .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table,
1392 #ifdef CONFIG_DEBUG_FS
1393         .debugfs_init = panthor_debugfs_init,
1394 #endif
1395 };
1396
1397 static int panthor_probe(struct platform_device *pdev)
1398 {
1399         struct panthor_device *ptdev;
1400
1401         ptdev = devm_drm_dev_alloc(&pdev->dev, &panthor_drm_driver,
1402                                    struct panthor_device, base);
1403         if (IS_ERR(ptdev))
1404                 return -ENOMEM;
1405
1406         platform_set_drvdata(pdev, ptdev);
1407
1408         return panthor_device_init(ptdev);
1409 }
1410
1411 static void panthor_remove(struct platform_device *pdev)
1412 {
1413         struct panthor_device *ptdev = platform_get_drvdata(pdev);
1414
1415         panthor_device_unplug(ptdev);
1416 }
1417
1418 static const struct of_device_id dt_match[] = {
1419         { .compatible = "rockchip,rk3588-mali" },
1420         { .compatible = "arm,mali-valhall-csf" },
1421         {}
1422 };
1423 MODULE_DEVICE_TABLE(of, dt_match);
1424
1425 static DEFINE_RUNTIME_DEV_PM_OPS(panthor_pm_ops,
1426                                  panthor_device_suspend,
1427                                  panthor_device_resume,
1428                                  NULL);
1429
1430 static struct platform_driver panthor_driver = {
1431         .probe = panthor_probe,
1432         .remove_new = panthor_remove,
1433         .driver = {
1434                 .name = "panthor",
1435                 .pm = pm_ptr(&panthor_pm_ops),
1436                 .of_match_table = dt_match,
1437         },
1438 };
1439
1440 /*
1441  * Workqueue used to cleanup stuff.
1442  *
1443  * We create a dedicated workqueue so we can drain on unplug and
1444  * make sure all resources are freed before the module is unloaded.
1445  */
1446 struct workqueue_struct *panthor_cleanup_wq;
1447
1448 static int __init panthor_init(void)
1449 {
1450         int ret;
1451
1452         ret = panthor_mmu_pt_cache_init();
1453         if (ret)
1454                 return ret;
1455
1456         panthor_cleanup_wq = alloc_workqueue("panthor-cleanup", WQ_UNBOUND, 0);
1457         if (!panthor_cleanup_wq) {
1458                 pr_err("panthor: Failed to allocate the workqueues");
1459                 ret = -ENOMEM;
1460                 goto err_mmu_pt_cache_fini;
1461         }
1462
1463         ret = platform_driver_register(&panthor_driver);
1464         if (ret)
1465                 goto err_destroy_cleanup_wq;
1466
1467         return 0;
1468
1469 err_destroy_cleanup_wq:
1470         destroy_workqueue(panthor_cleanup_wq);
1471
1472 err_mmu_pt_cache_fini:
1473         panthor_mmu_pt_cache_fini();
1474         return ret;
1475 }
1476 module_init(panthor_init);
1477
1478 static void __exit panthor_exit(void)
1479 {
1480         platform_driver_unregister(&panthor_driver);
1481         destroy_workqueue(panthor_cleanup_wq);
1482         panthor_mmu_pt_cache_fini();
1483 }
1484 module_exit(panthor_exit);
1485
1486 MODULE_AUTHOR("Panthor Project Developers");
1487 MODULE_DESCRIPTION("Panthor DRM Driver");
1488 MODULE_LICENSE("Dual MIT/GPL");
This page took 0.120736 seconds and 4 git commands to generate.