Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/panfrost: Add a PANFROST_SYNC_BO ioctl

This will be used by the UMD to synchronize CPU-cached mappings when
the UMD can't do it directly (no usermode cache maintenance instruction
on Arm32).

v2:
- Add more to the commit message
- Change the flags to better match the drm_gem_shmem_sync semantics

v3:
- Add Steve's R-b

v4:
- No changes

v5:
- Drop Steve's R-b (semantics changes requiring a new review)

v6:
- Bail out early in panfrost_ioctl_sync_bo() if op_count is zero

v7:
- Hand-roll our own bo_sync() helper

v8:
- Collect R-b

Signed-off-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Link: https://patch.msgid.link/20251208100841.730527-11-boris.brezillon@collabora.com
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>

authored by

Faith Ekstrand and committed by
Boris Brezillon
7be45f54 2396d65d

+182
+51
drivers/gpu/drm/panfrost/panfrost_drv.c
··· 580 580 return panfrost_jm_ctx_destroy(file, args->handle); 581 581 } 582 582 583 + static int panfrost_ioctl_sync_bo(struct drm_device *ddev, void *data, 584 + struct drm_file *file) 585 + { 586 + struct drm_panfrost_sync_bo *args = data; 587 + struct drm_panfrost_bo_sync_op *ops; 588 + struct drm_gem_object *obj; 589 + int ret; 590 + u32 i; 591 + 592 + if (args->pad) 593 + return -EINVAL; 594 + 595 + if (!args->op_count) 596 + return 0; 597 + 598 + ops = kvmalloc_array(args->op_count, sizeof(*ops), GFP_KERNEL); 599 + if (!ops) { 600 + DRM_DEBUG("Failed to allocate incoming BO sync ops array\n"); 601 + return -ENOMEM; 602 + } 603 + 604 + if (copy_from_user(ops, (void __user *)(uintptr_t)args->ops, 605 + args->op_count * sizeof(*ops))) { 606 + DRM_DEBUG("Failed to copy in BO sync ops\n"); 607 + ret = -EFAULT; 608 + goto err_ops; 609 + } 610 + 611 + for (i = 0; i < args->op_count; i++) { 612 + obj = drm_gem_object_lookup(file, ops[i].handle); 613 + if (!obj) { 614 + ret = -ENOENT; 615 + goto err_ops; 616 + } 617 + 618 + ret = panfrost_gem_sync(obj, ops[i].type, 619 + ops[i].offset, ops[i].size); 620 + 621 + drm_gem_object_put(obj); 622 + 623 + if (ret) 624 + goto err_ops; 625 + } 626 + 627 + err_ops: 628 + kvfree(ops); 629 + 630 + return ret; 631 + } 632 + 583 633 int panfrost_unstable_ioctl_check(void) 584 634 { 585 635 if (!unstable_ioctls) ··· 699 649 PANFROST_IOCTL(SET_LABEL_BO, set_label_bo, DRM_RENDER_ALLOW), 700 650 PANFROST_IOCTL(JM_CTX_CREATE, jm_ctx_create, DRM_RENDER_ALLOW), 701 651 PANFROST_IOCTL(JM_CTX_DESTROY, jm_ctx_destroy, DRM_RENDER_ALLOW), 652 + PANFROST_IOCTL(SYNC_BO, sync_bo, DRM_RENDER_ALLOW), 702 653 }; 703 654 704 655 static void panfrost_gpu_show_fdinfo(struct panfrost_device *pfdev,
+84
drivers/gpu/drm/panfrost/panfrost_gem.c
··· 507 507 kfree_const(old_label); 508 508 } 509 509 510 + int 511 + panfrost_gem_sync(struct drm_gem_object *obj, u32 type, u32 offset, u32 size) 512 + { 513 + struct panfrost_gem_object *bo = to_panfrost_bo(obj); 514 + struct drm_gem_shmem_object *shmem = &bo->base; 515 + const struct drm_device *dev = shmem->base.dev; 516 + struct sg_table *sgt; 517 + struct scatterlist *sgl; 518 + unsigned int count; 519 + 520 + /* Make sure the range is in bounds. */ 521 + if (offset + size < offset || offset + size > shmem->base.size) 522 + return -EINVAL; 523 + 524 + /* Disallow CPU-cache maintenance on imported buffers. */ 525 + if (drm_gem_is_imported(&shmem->base)) 526 + return -EINVAL; 527 + 528 + switch (type) { 529 + case PANFROST_BO_SYNC_CPU_CACHE_FLUSH: 530 + case PANFROST_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE: 531 + break; 532 + 533 + default: 534 + return -EINVAL; 535 + } 536 + 537 + /* Don't bother if it's WC-mapped */ 538 + if (shmem->map_wc) 539 + return 0; 540 + 541 + /* Nothing to do if the size is zero. */ 542 + if (size == 0) 543 + return 0; 544 + 545 + sgt = drm_gem_shmem_get_pages_sgt(shmem); 546 + if (IS_ERR(sgt)) 547 + return PTR_ERR(sgt); 548 + 549 + for_each_sgtable_dma_sg(sgt, sgl, count) { 550 + if (size == 0) 551 + break; 552 + 553 + dma_addr_t paddr = sg_dma_address(sgl); 554 + size_t len = sg_dma_len(sgl); 555 + 556 + if (len <= offset) { 557 + offset -= len; 558 + continue; 559 + } 560 + 561 + paddr += offset; 562 + len -= offset; 563 + len = min_t(size_t, len, size); 564 + size -= len; 565 + offset = 0; 566 + 567 + /* It's unclear whether dma_sync_xxx() is the right API to do CPU 568 + * cache maintenance given an IOMMU can register their own 569 + * implementation doing more than just CPU cache flushes/invalidation, 570 + * and what we really care about here is CPU caches only, but that's 571 + * the best we have that is both arch-agnostic and does at least the 572 + * CPU cache maintenance on a <page,offset,size> tuple. 573 + * 574 + * Also, I wish we could do a single 575 + * 576 + * dma_sync_single_for_device(BIDIR) 577 + * 578 + * and get a flush+invalidate, but that's not how it's implemented 579 + * in practice (at least on arm64), so we have to make it 580 + * 581 + * dma_sync_single_for_device(TO_DEVICE) 582 + * dma_sync_single_for_cpu(FROM_DEVICE) 583 + * 584 + * for the flush+invalidate case. 585 + */ 586 + dma_sync_single_for_device(dev->dev, paddr, len, DMA_TO_DEVICE); 587 + if (type == PANFROST_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE) 588 + dma_sync_single_for_cpu(dev->dev, paddr, len, DMA_FROM_DEVICE); 589 + } 590 + 591 + return 0; 592 + } 593 + 510 594 void 511 595 panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label) 512 596 {
+2
drivers/gpu/drm/panfrost/panfrost_gem.h
··· 153 153 void panfrost_gem_shrinker_cleanup(struct drm_device *dev); 154 154 155 155 void panfrost_gem_set_label(struct drm_gem_object *obj, const char *label); 156 + int panfrost_gem_sync(struct drm_gem_object *obj, u32 type, 157 + u32 offset, u32 size); 156 158 void panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label); 157 159 158 160 #ifdef CONFIG_DEBUG_FS
+45
include/uapi/drm/panfrost_drm.h
··· 24 24 #define DRM_PANFROST_SET_LABEL_BO 0x09 25 25 #define DRM_PANFROST_JM_CTX_CREATE 0x0a 26 26 #define DRM_PANFROST_JM_CTX_DESTROY 0x0b 27 + #define DRM_PANFROST_SYNC_BO 0x0c 27 28 28 29 #define DRM_IOCTL_PANFROST_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_SUBMIT, struct drm_panfrost_submit) 29 30 #define DRM_IOCTL_PANFROST_WAIT_BO DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_WAIT_BO, struct drm_panfrost_wait_bo) ··· 36 35 #define DRM_IOCTL_PANFROST_SET_LABEL_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_SET_LABEL_BO, struct drm_panfrost_set_label_bo) 37 36 #define DRM_IOCTL_PANFROST_JM_CTX_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_JM_CTX_CREATE, struct drm_panfrost_jm_ctx_create) 38 37 #define DRM_IOCTL_PANFROST_JM_CTX_DESTROY DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_JM_CTX_DESTROY, struct drm_panfrost_jm_ctx_destroy) 38 + #define DRM_IOCTL_PANFROST_SYNC_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_SYNC_BO, struct drm_panfrost_sync_bo) 39 39 40 40 /* 41 41 * Unstable ioctl(s): only exposed when the unsafe unstable_ioctls module ··· 308 306 * NULL is permitted and means clear the label. 309 307 */ 310 308 __u64 label; 309 + }; 310 + 311 + /* Valid flags to pass to drm_panfrost_bo_sync_op */ 312 + #define PANFROST_BO_SYNC_CPU_CACHE_FLUSH 0 313 + #define PANFROST_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE 1 314 + 315 + /** 316 + * struct drm_panthor_bo_flush_map_op - BO map sync op 317 + */ 318 + struct drm_panfrost_bo_sync_op { 319 + /** @handle: Handle of the buffer object to sync. */ 320 + __u32 handle; 321 + 322 + /** @type: Type of sync operation. */ 323 + __u32 type; 324 + 325 + /** 326 + * @offset: Offset into the BO at which the sync range starts. 327 + * 328 + * This will be rounded down to the nearest cache line as needed. 329 + */ 330 + __u32 offset; 331 + 332 + /** 333 + * @size: Size of the range to sync 334 + * 335 + * @size + @offset will be rounded up to the nearest cache line as 336 + * needed. 337 + */ 338 + __u32 size; 339 + }; 340 + 341 + /** 342 + * struct drm_panfrost_sync_bo - ioctl argument for syncing BO maps 343 + */ 344 + struct drm_panfrost_sync_bo { 345 + /** Array of struct drm_panfrost_bo_sync_op */ 346 + __u64 ops; 347 + 348 + /** Number of BO sync ops */ 349 + __u32 op_count; 350 + 351 + __u32 pad; 311 352 }; 312 353 313 354 /* Definitions for coredump decoding in user space */