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