From: Boris Brezillon <[email protected]> Extensions to Panthor uAPI: - New IOCTL for user space to provide protected FW memory. - New query for checking protected rendering availability/status and requirements. - Extends group creation to allow user space to provide a protected suspend buffer.
The Mali GPU FW needs some protected memory when executing in protected mode. This FW memory section is assigned a VA during device init. A user space process with the needed privileges (CAP_SYS_MODULE) must provide a suitable memory buffer before the Mali GPU is capable of executing in protected mode. Processes who want to execute in protected mode must also ensure they pass a protected suspend buffer during group creation. Added panthor_kernel_bo_import() to allow user provided buffers. Refactor panthor_kernel_bo_create() to allow shared code with the new import variant. Signed-off-by: Boris Brezillon <[email protected]> Co-developed-by: Ketil Johnsen <[email protected]> Signed-off-by: Ketil Johnsen <[email protected]> --- drivers/gpu/drm/panthor/panthor_device.h | 3 + drivers/gpu/drm/panthor/panthor_drv.c | 23 +++- drivers/gpu/drm/panthor/panthor_fw.c | 154 ++++++++++++++++++----- drivers/gpu/drm/panthor/panthor_fw.h | 2 + drivers/gpu/drm/panthor/panthor_gem.c | 102 +++++++++------ drivers/gpu/drm/panthor/panthor_gem.h | 7 +- drivers/gpu/drm/panthor/panthor_sched.c | 45 ++++++- include/uapi/drm/panthor_drm.h | 85 ++++++++++++- 8 files changed, 347 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h index e5df42f095717..c3fab0a1b77b2 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -351,6 +351,9 @@ struct panthor_device { * in panthor_vm_lock_region() will ensure this is enough. */ struct rw_semaphore lock; + + /** @info: Protected mode info. */ + struct drm_panthor_protm_info info; } protm; }; diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index e18ee2d7a8e6f..6be9f33483e7b 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -178,11 +178,13 @@ panthor_get_uobj_array(const struct drm_panthor_obj_array *in, u32 min_stride, PANTHOR_UOBJ_DECL(struct drm_panthor_mmu_info, page_size_bitmap), \ PANTHOR_UOBJ_DECL(struct drm_panthor_timestamp_info, current_timestamp), \ PANTHOR_UOBJ_DECL(struct drm_panthor_group_priorities_info, pad), \ + PANTHOR_UOBJ_DECL(struct drm_panthor_protm_info, pad), \ PANTHOR_UOBJ_DECL(struct drm_panthor_sync_op, timeline_value), \ PANTHOR_UOBJ_DECL(struct drm_panthor_queue_submit, syncs), \ PANTHOR_UOBJ_DECL(struct drm_panthor_queue_create, ringbuf_size), \ PANTHOR_UOBJ_DECL(struct drm_panthor_vm_bind_op, syncs), \ - PANTHOR_UOBJ_DECL(struct drm_panthor_bo_sync_op, size)) + PANTHOR_UOBJ_DECL(struct drm_panthor_bo_sync_op, size), \ + PANTHOR_UOBJ_DECL(struct drm_panthor_protm_init, pad)) /** * PANTHOR_UOBJ_SET() - Copy a kernel object to a user object. @@ -959,6 +961,10 @@ static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct d args->size = sizeof(ptdev->mmu_info); return 0; + case DRM_PANTHOR_DEV_QUERY_PROTM_INFO: + args->size = sizeof(ptdev->protm.info); + return 0; + default: return -EINVAL; } @@ -992,6 +998,9 @@ static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct d case DRM_PANTHOR_DEV_QUERY_MMU_INFO: return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->mmu_info); + case DRM_PANTHOR_DEV_QUERY_PROTM_INFO: + return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->protm.info); + default: return -EINVAL; } @@ -1589,6 +1598,12 @@ static int panthor_ioctl_bo_query_info(struct drm_device *ddev, void *data, return 0; } +static int panthor_ioctl_protm_init(struct drm_device *ddev, void *data, + struct drm_file *file) +{ + return panthor_fw_protm_init(file, data); +} + static int panthor_open(struct drm_device *ddev, struct drm_file *file) { @@ -1665,6 +1680,7 @@ static const struct drm_ioctl_desc panthor_drm_driver_ioctls[] = { PANTHOR_IOCTL(SET_USER_MMIO_OFFSET, set_user_mmio_offset, DRM_RENDER_ALLOW), PANTHOR_IOCTL(BO_SYNC, bo_sync, DRM_RENDER_ALLOW), PANTHOR_IOCTL(BO_QUERY_INFO, bo_query_info, DRM_RENDER_ALLOW), + PANTHOR_IOCTL(PROTM_INIT, protm_init, DRM_RENDER_ALLOW), }; static int panthor_mmap(struct file *filp, struct vm_area_struct *vma) @@ -1785,6 +1801,9 @@ static void panthor_debugfs_init(struct drm_minor *minor) * - 1.8 - extends DEV_QUERY_TIMESTAMP_INFO with flags * - 1.9 - adds DRM_PANTHOR_DEV_QUERY_MMU_INFO query * - adds DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE flag + * - 1.10 - adds DRM_IOCTL_PANTHOR_PROTM_INIT ioctl + * - adds DRM_PANTHOR_DEV_QUERY_PROTM_INFO query + * - adds drm_panthor_group_create::protected_suspend_bo_handle */ static const struct drm_driver panthor_drm_driver = { .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ | @@ -1798,7 +1817,7 @@ static const struct drm_driver panthor_drm_driver = { .name = "panthor", .desc = "Panthor DRM driver", .major = 1, - .minor = 9, + .minor = 10, .gem_prime_import_sg_table = panthor_gem_prime_import_sg_table, .gem_prime_import = panthor_gem_prime_import, diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index 76792f9175b57..d282aef84ce4f 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -13,8 +13,10 @@ #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/capability.h> #include <drm/drm_drv.h> +#include <drm/drm_file.h> #include <drm/drm_managed.h> #include <drm/drm_print.h> @@ -198,6 +200,12 @@ struct panthor_fw_section { /** @size: Size of @buf in bytes. */ size_t size; } data; + + /** @size: Section size. */ + size_t size; + + /** @va: Section VA. */ + u32 va; }; #define CSF_MCU_SHARED_REGION_START 0x04000000ULL @@ -246,6 +254,9 @@ struct panthor_fw { /** @shared_section: The section containing the FW interfaces. */ struct panthor_fw_section *shared_section; + /** @protm_section: The protected mode section. */ + struct panthor_fw_section *protm_section; + /** @iface: FW interfaces. */ struct panthor_fw_iface iface; @@ -255,6 +266,9 @@ struct panthor_fw { struct delayed_work ping_work; } watchdog; + /** @protm_init_lock: Used to serialize protm initialization. */ + struct mutex protm_init_lock; + /** * @req_waitqueue: FW request waitqueue. * @@ -542,6 +556,30 @@ panthor_fw_alloc_suspend_buf_mem(struct panthor_device *ptdev, size_t size) "FW suspend buffer"); } +static u32 section_vm_map_flags(const struct panthor_fw_section *section) +{ + u32 cache_mode = section->flags & CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_MASK; + u32 vm_map_flags = 0; + + if (!(section->flags & CSF_FW_BINARY_IFACE_ENTRY_WR)) + vm_map_flags |= DRM_PANTHOR_VM_BIND_OP_MAP_READONLY; + + if (!(section->flags & CSF_FW_BINARY_IFACE_ENTRY_EX)) + vm_map_flags |= DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC; + + /* TODO: CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_*_COHERENT are mapped to + * non-cacheable for now. We might want to introduce a new + * IOMMU_xxx flag (or abuse IOMMU_MMIO, which maps to device + * memory and is currently not used by our driver) for + * AS_MEMATTR_AARCH64_SHARED memory, so we can take benefit + * of IO-coherent systems. + */ + if (cache_mode != CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_CACHED) + vm_map_flags |= DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED; + + return vm_map_flags; +} + static int panthor_fw_load_section_entry(struct panthor_device *ptdev, const struct firmware *fw, struct panthor_fw_binary_iter *iter, @@ -550,7 +588,6 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev, ssize_t vm_pgsz = panthor_vm_page_size(ptdev->fw->vm); struct panthor_fw_binary_section_entry_hdr hdr; struct panthor_fw_section *section; - u32 section_size; u32 name_len; int ret; @@ -588,12 +625,6 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev, return -EINVAL; } - if (hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_PROT) { - drm_warn(&ptdev->base, - "Firmware protected mode entry is not supported, ignoring"); - return 0; - } - if (hdr.va.start == CSF_MCU_SHARED_REGION_START && !(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_SHARED)) { drm_err(&ptdev->base, @@ -632,36 +663,34 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev, section->name = name; } - section_size = hdr.va.end - hdr.va.start; - if (section_size) { - u32 cache_mode = hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_MASK; - u32 vm_map_flags = 0; - u64 va = hdr.va.start; + section->size = hdr.va.end - hdr.va.start; + section->va = hdr.va.start; - if (!(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_WR)) - vm_map_flags |= DRM_PANTHOR_VM_BIND_OP_MAP_READONLY; + if (hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_PROT) { + if (ptdev->fw->protm_section) { + drm_err(&ptdev->base, "Only one protected section supported\n"); + return -EINVAL; + } - if (!(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_EX)) - vm_map_flags |= DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC; + ptdev->protm.info.fw_protected_sections_size = ALIGN(section->size, vm_pgsz); + ptdev->fw->protm_section = section; + } - /* TODO: CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_*_COHERENT are mapped to - * non-cacheable for now. We might want to introduce a new - * IOMMU_xxx flag (or abuse IOMMU_MMIO, which maps to device - * memory and is currently not used by our driver) for - * AS_MEMATTR_AARCH64_SHARED memory, so we can take benefit - * of IO-coherent systems. - */ - if (cache_mode != CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_CACHED) - vm_map_flags |= DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED; + /* Defer the section->mem creation if this is a protected entry. + * This will be populated when DRM_IOCTL_PANTHOR_PROTM_INIT is called. + */ + if (section->size && !(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_PROT)) { + u32 vm_map_flags = section_vm_map_flags(section); section->mem = panthor_kernel_bo_create(ptdev, panthor_fw_vm(ptdev), - section_size, + section->size, DRM_PANTHOR_BO_NO_MMAP, - vm_map_flags, va, "FW section"); + vm_map_flags, section->va, + "FW section"); if (IS_ERR(section->mem)) return PTR_ERR(section->mem); - if (drm_WARN_ON(&ptdev->base, section->mem->va_node.start != hdr.va.start)) + if (drm_WARN_ON(&ptdev->base, section->mem->va_node.start != section->va)) return -EINVAL; if (section->flags & CSF_FW_BINARY_IFACE_ENTRY_SHARED) { @@ -942,6 +971,11 @@ static int panthor_init_csg_iface(struct panthor_device *ptdev, return -EINVAL; } + if (!csg_idx) { + ptdev->protm.info.group_protected_suspend_buf_size = + csg_iface->control->protm_suspend_size; + } + if (csg_idx > 0) { struct panthor_fw_csg_iface *first_csg_iface = panthor_fw_get_csg_iface(ptdev, 0); @@ -1529,6 +1563,66 @@ int panthor_fw_protm_exit(struct panthor_device *ptdev) return panthor_fw_protm_exit_wait(ptdev, 500); } +int panthor_fw_protm_init(struct drm_file *file, + struct drm_panthor_protm_init *args) +{ + struct panthor_file *pfile = file->driver_priv; + struct panthor_device *ptdev = pfile->ptdev; + struct panthor_fw_section *protm_section = ptdev->fw->protm_section; + struct drm_gem_object *obj; + u32 vm_map_flags; + int cookie, ret = 0; + + if (!capable(CAP_SYS_MODULE)) + return -EPERM; + + if (args->pad) + return -EINVAL; + + if (!protm_section || !protm_section->size) + return -EINVAL; + + guard(mutex)(&ptdev->fw->protm_init_lock); + + if (ptdev->protm.info.state & DRM_PANTHOR_PROTM_INITIALIZED) + return 0; + + if (!drm_dev_enter(&ptdev->base, &cookie)) + return -ENODEV; + + obj = drm_gem_object_lookup(file, args->fw_protected_sections_bo_handle); + if (!obj) { + ret = -ENOENT; + goto out_dev_exit; + } + + if (obj->size < ptdev->protm.info.fw_protected_sections_size) { + ret = -EINVAL; + goto out_gem_put; + } + + vm_map_flags = section_vm_map_flags(protm_section); + + protm_section->mem = panthor_kernel_bo_import(ptdev, panthor_fw_vm(ptdev), + to_panthor_bo(obj), + vm_map_flags, protm_section->va, + protm_section->size); + if (IS_ERR(protm_section->mem)) { + ret = PTR_ERR(protm_section->mem); + protm_section->mem = NULL; + goto out_gem_put; + } + + ptdev->protm.info.state |= DRM_PANTHOR_PROTM_INITIALIZED; + +out_gem_put: + drm_gem_object_put(obj); + +out_dev_exit: + drm_dev_exit(cookie); + return ret; +} + /** * panthor_fw_init() - Initialize FW related data. * @ptdev: Device. @@ -1550,6 +1644,10 @@ int panthor_fw_init(struct panthor_device *ptdev) INIT_LIST_HEAD(&fw->sections); INIT_DELAYED_WORK(&fw->watchdog.ping_work, panthor_fw_ping_work); + ret = drmm_mutex_init(&ptdev->base, &fw->protm_init_lock); + if (ret) + return ret; + irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "job"); if (irq <= 0) return -ENODEV; diff --git a/drivers/gpu/drm/panthor/panthor_fw.h b/drivers/gpu/drm/panthor/panthor_fw.h index 78658d64b807e..dbd3e58f04eb6 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.h +++ b/drivers/gpu/drm/panthor/panthor_fw.h @@ -529,6 +529,8 @@ static inline int panthor_fw_resume(struct panthor_device *ptdev) int panthor_fw_init(struct panthor_device *ptdev); void panthor_fw_unplug(struct panthor_device *ptdev); +int panthor_fw_protm_init(struct drm_file *file, + struct drm_panthor_protm_init *args); int panthor_fw_protm_enter(struct panthor_device *ptdev); int panthor_fw_protm_exit(struct panthor_device *ptdev); int panthor_fw_protm_exit_wait(struct panthor_device *ptdev, diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 9855df7381947..69ef4b6012b4f 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -74,14 +74,14 @@ static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) mutex_unlock(&ptdev->gems.lock); } -static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) +static void panthor_gem_debugfs_add_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) { - bo->debugfs.flags = usage_flags; - panthor_gem_debugfs_bo_add(bo); + atomic_or(usage_flags, &bo->debugfs.flags); } #else +static void panthor_gem_debugfs_bo_add(struct panthor_gem_object *bo) {} static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) {} -static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {} +static void panthor_gem_debugfs_add_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {} static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) {} #endif @@ -1027,7 +1027,7 @@ panthor_gem_create(struct drm_device *dev, size_t size, uint32_t flags, bo->base.resv = bo->exclusive_vm_root_gem->resv; } - panthor_gem_debugfs_set_usage_flags(bo, usage_flags); + panthor_gem_debugfs_bo_add(bo); return bo; err_put: @@ -1253,7 +1253,9 @@ void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo) panthor_kernel_bo_vunmap(bo); drm_WARN_ON(bo->obj->dev, - to_panthor_bo(bo->obj)->exclusive_vm_root_gem != panthor_vm_root_gem(vm)); + to_panthor_bo(bo->obj)->exclusive_vm_root_gem && + (to_panthor_bo(bo->obj)->exclusive_vm_root_gem != + panthor_vm_root_gem(vm))); panthor_vm_unmap_range(vm, bo->va_node.start, bo->va_node.size); panthor_vm_free_va(vm, &bo->va_node); if (vm == panthor_fw_vm(ptdev)) @@ -1264,46 +1266,32 @@ void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo) } /** - * panthor_kernel_bo_create() - Create and map a GEM object to a VM + * panthor_kernel_bo_import() - Create a kernel BO from an existing GEM object * @ptdev: Device. * @vm: VM to map the GEM to. - * @size: Size of the buffer object. - * @bo_flags: Combination of drm_panthor_bo_flags flags. + * @bo: BO to use for our kernel BO. * @vm_map_flags: Combination of drm_panthor_vm_bind_op_flags (only those * that are related to map operations). * @gpu_va: GPU address assigned when mapping to the VM. * If gpu_va == PANTHOR_VM_KERNEL_AUTO_VA, the virtual address will be * automatically allocated. - * @name: Descriptive label of the BO's contents + * @vm_map_size: Size of the BO to map to the VM. * * Return: A valid pointer in case of success, an ERR_PTR() otherwise. */ struct panthor_kernel_bo * -panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, - size_t size, u32 bo_flags, u32 vm_map_flags, - u64 gpu_va, const char *name) +panthor_kernel_bo_import(struct panthor_device *ptdev, struct panthor_vm *vm, + struct panthor_gem_object *bo, + u32 vm_map_flags, u64 gpu_va, u32 vm_map_size) { struct panthor_kernel_bo *kbo; - struct panthor_gem_object *bo; - u32 debug_flags = PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL; int ret; - if (drm_WARN_ON(&ptdev->base, !vm)) - return ERR_PTR(-EINVAL); - kbo = kzalloc_obj(*kbo); if (!kbo) return ERR_PTR(-ENOMEM); - if (vm == panthor_fw_vm(ptdev)) - debug_flags |= PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED; - - bo = panthor_gem_create(&ptdev->base, size, bo_flags, vm, debug_flags); - if (IS_ERR(bo)) { - ret = PTR_ERR(bo); - goto err_free_kbo; - } - + drm_gem_object_get(&bo->base); kbo->obj = &bo->base; if (vm == panthor_fw_vm(ptdev)) { @@ -1312,24 +1300,26 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, goto err_put_obj; } - panthor_gem_kernel_bo_set_label(kbo, name); - /* The system and GPU MMU page size might differ, which becomes a * problem for FW sections that need to be mapped at explicit address * since our PAGE_SIZE alignment might cover a VA range that's * expected to be used for another section. * Make sure we never map more than we need. */ - size = ALIGN(size, panthor_vm_page_size(vm)); - ret = panthor_vm_alloc_va(vm, gpu_va, size, &kbo->va_node); + vm_map_size = ALIGN(vm_map_size, panthor_vm_page_size(vm)); + ret = panthor_vm_alloc_va(vm, gpu_va, vm_map_size, &kbo->va_node); if (ret) goto err_unpin; - ret = panthor_vm_map_bo_range(vm, bo, 0, size, kbo->va_node.start, vm_map_flags); + ret = panthor_vm_map_bo_range(vm, bo, 0, vm_map_size, + kbo->va_node.start, vm_map_flags); if (ret) goto err_free_va; kbo->vm = panthor_vm_get(vm); + if (vm == panthor_fw_vm(ptdev)) + panthor_gem_debugfs_add_usage_flags(bo, PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED); + return kbo; err_free_va: @@ -1341,12 +1331,54 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, err_put_obj: drm_gem_object_put(&bo->base); - -err_free_kbo: kfree(kbo); return ERR_PTR(ret); } +/** + * panthor_kernel_bo_create() - Create and map a GEM object to a VM + * @ptdev: Device. + * @vm: VM to map the GEM to. + * @size: Size of the buffer object. + * @bo_flags: Combination of drm_panthor_bo_flags flags. + * @vm_map_flags: Combination of drm_panthor_vm_bind_op_flags (only those + * that are related to map operations). + * @gpu_va: GPU address assigned when mapping to the VM. + * If gpu_va == PANTHOR_VM_KERNEL_AUTO_VA, the virtual address will be + * automatically allocated. + * @name: Descriptive label of the BO's contents + * + * Return: A valid pointer in case of success, an ERR_PTR() otherwise. + */ +struct panthor_kernel_bo * +panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, + size_t size, u32 bo_flags, u32 vm_map_flags, + u64 gpu_va, const char *name) +{ + struct panthor_kernel_bo *kbo; + struct panthor_gem_object *bo; + + if (drm_WARN_ON(&ptdev->base, !vm)) + return ERR_PTR(-EINVAL); + + bo = panthor_gem_create(&ptdev->base, size, bo_flags, vm, 0); + if (IS_ERR(bo)) + return ERR_CAST(bo); + + kbo = panthor_kernel_bo_import(ptdev, vm, bo, vm_map_flags, gpu_va, + size); + if (!IS_ERR(kbo)) { + panthor_gem_debugfs_add_usage_flags(bo, PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL); + panthor_gem_kernel_bo_set_label(kbo, name); + } + + /* panthor_kernel_bo_import() acquires a GEM ref if the import succeeds, so + * we can release it unconditionally here. + */ + drm_gem_object_put(&bo->base); + return kbo; +} + /** * panthor_dummy_bo_create() - Create a Panthor BO meant to back sparse bindings. * @ptdev: Device. @@ -1642,9 +1674,9 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo, enum panthor_gem_reclaim_state reclaim_state = bo->reclaim_state; unsigned int refcount = kref_read(&bo->base.refcount); int reclaimed_count = atomic_read(&bo->reclaimed_count); + u32 gem_usage_flags = atomic_read(&bo->debugfs.flags); char creator_info[32] = {}; size_t resident_size; - u32 gem_usage_flags = bo->debugfs.flags; u32 gem_state_flags = 0; /* Skip BOs being destroyed. */ diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index 5ae37d0d3646f..7e88f5dcbff54 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -62,7 +62,7 @@ struct panthor_gem_debugfs { } creator; /** @flags: Combination of panthor_debugfs_gem_usage_flags flags */ - u32 flags; + atomic_t flags; }; /** @@ -318,6 +318,11 @@ panthor_kernel_bo_vunmap(struct panthor_kernel_bo *bo) } } +struct panthor_kernel_bo * +panthor_kernel_bo_import(struct panthor_device *ptdev, struct panthor_vm *vm, + struct panthor_gem_object *bo, + u32 vm_map_flags, u64 gpu_va, u32 vm_map_size); + struct panthor_kernel_bo * panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, size_t size, u32 bo_flags, u32 vm_map_flags, diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index efa53b0a05d38..15c7bb34a865d 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -1508,10 +1508,15 @@ cs_slot_process_protm_pending_event_locked(struct panthor_device *ptdev, if (!group) return; - /* Do not allow user space work to switch into protected mode, as we - * do not fully support this quite yet. + /* Do not allow user space work to switch into protected mode if we + * do not support protected mode on this device. + * User space should query (and init) this support before attempting + * to use such GPU instructions. */ - group->fatal_queues |= BIT(cs_id); + if (!(ptdev->protm.info.state & DRM_PANTHOR_PROTM_INITIALIZED)) + group->fatal_queues |= BIT(cs_id); + else + group->protm_pending_queues |= BIT(cs_id); sched_queue_delayed_work(sched, tick, 0); } @@ -3962,6 +3967,7 @@ static void add_group_kbo_sizes(struct panthor_device *ptdev, } #define MAX_GROUPS_PER_POOL 128 +#define GROUP_CREATE_FLAGS DRM_PANTHOR_GROUP_CREATE_PROTECTED int panthor_group_create(struct drm_file *file, const struct drm_panthor_group_create *group_args, @@ -3976,9 +3982,6 @@ int panthor_group_create(struct drm_file *file, u32 gid, i, suspend_size; int ret; - if (group_args->pad) - return -EINVAL; - if (group_args->priority >= PANTHOR_CSG_PRIORITY_COUNT) return -EINVAL; @@ -4031,6 +4034,36 @@ int panthor_group_create(struct drm_file *file, goto err_put_group; } + if (group_args->protected_suspend_bo_handle) { + struct drm_gem_object *obj; + + obj = drm_gem_object_lookup(file, group_args->protected_suspend_bo_handle); + if (!obj) { + ret = -ENOENT; + goto err_put_group; + } + + if (obj->size < ptdev->protm.info.group_protected_suspend_buf_size) { + drm_gem_object_put(obj); + ret = -EINVAL; + goto err_put_group; + } + + suspend_size = csg_iface->control->protm_suspend_size; + group->protm_suspend_buf = + panthor_kernel_bo_import(ptdev, panthor_fw_vm(ptdev), + to_panthor_bo(obj), + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC, + PANTHOR_VM_KERNEL_AUTO_VA, + suspend_size); + drm_gem_object_put(obj); + if (IS_ERR(group->protm_suspend_buf)) { + ret = PTR_ERR(group->protm_suspend_buf); + group->protm_suspend_buf = NULL; + goto err_put_group; + } + } + group->syncobjs = panthor_kernel_bo_create(ptdev, group->vm, group_args->queues.count * sizeof(struct panthor_syncobj_64b), diff --git a/include/uapi/drm/panthor_drm.h b/include/uapi/drm/panthor_drm.h index a2ff0f4ec6915..a0ed16041e178 100644 --- a/include/uapi/drm/panthor_drm.h +++ b/include/uapi/drm/panthor_drm.h @@ -154,6 +154,11 @@ enum drm_panthor_ioctl_id { * This is useful for imported BOs. */ DRM_PANTHOR_BO_QUERY_INFO, + + /** + * @DRM_PANTHOR_PROTM_INIT: Device-wide initialize of protected mode. + */ + DRM_PANTHOR_PROTM_INIT, }; /** @@ -256,6 +261,11 @@ enum drm_panthor_dev_query_type { /** @DRM_PANTHOR_DEV_QUERY_MMU_INFO: Query MMU information. */ DRM_PANTHOR_DEV_QUERY_MMU_INFO, + + /** + * @DRM_PANTHOR_DEV_QUERY_PROTM_INFO: Query supported protected rendering information. + */ + DRM_PANTHOR_DEV_QUERY_PROTM_INFO, }; /** @@ -517,6 +527,51 @@ struct drm_panthor_group_priorities_info { __u8 pad[3]; }; +/** + * enum drm_panthor_protm_state_flags - Describes the state of the protected mode feature. + * + * List of GPU states which can be used by the GPU to access protected memory. + */ +enum drm_panthor_protm_state_flags { + /** + * @DRM_PANTHOR_PROTM_INITIALIZED: Device-wide initialization of the + * protected mode feature is done. + */ + DRM_PANTHOR_PROTM_INITIALIZED = 1 << 0, +}; + +/** + * struct drm_panthor_protm_info - Protected mode info. + * + * Structure grouping all queryable information relating to protected mode. + */ +struct drm_panthor_protm_info { + /** + * @state: Combination of enum drm_panthor_protm_state_flags flags. + */ + __u32 state; + + /** + * @fw_protected_sections_size: Size of all the protected FW sections. + * + * Size of the protected buffer to pass through + * DRM_IOCTL_PANTHOR_PROTM_INIT. + */ + __u32 fw_protected_sections_size; + + /** + * @group_protected_suspend_buf_size: Size of the group suspend buffer. + * + * This must be used to allocate a protected BO that's big enough to use + * as a protected suspend buffer when a group supports protected + * rendering. + */ + __u32 group_protected_suspend_buf_size; + + /** @pad: MBZ. */ + __u32 pad; +}; + /** * struct drm_panthor_dev_query - Arguments passed to DRM_PANTHOR_IOCTL_DEV_QUERY */ @@ -901,8 +956,14 @@ struct drm_panthor_group_create { /** @priority: Group priority (see enum drm_panthor_group_priority). */ __u8 priority; - /** @pad: Padding field, MBZ. */ - __u32 pad; + /** + * @protected_suspend_bo_handle: BO to use as a protected suspend buffer. + * + * This BO must have been allocated from a protected DMA-BUF heap and + * imported in panthor. It's size must be at least + * drm_panthor_protm_info::group_protected_suspend_buf_size. + */ + __u32 protected_suspend_bo_handle; /** * @compute_core_mask: Mask encoding cores that can be used for compute jobs. @@ -1270,6 +1331,24 @@ struct drm_panthor_bo_query_info { __u32 pad; }; +/** + * struct drm_panthor_protm_init - Protected mode initialization arguments. + */ +struct drm_panthor_protm_init { + /** + * @fw_protected_sections_bo_handle: Handle of the BO to use for the FW protected + * sections. + * + * This BO must have been allocated from a protected DMA-BUF heap and + * imported in panthor. It's size must be at least + * drm_panthor_protm_info::fw_protected_sections_size. + */ + __u32 fw_protected_sections_bo_handle; + + /** @pad: MBZ. */ + __u32 pad; +}; + /** * DRM_IOCTL_PANTHOR() - Build a Panthor IOCTL number * @__access: Access type. Must be R, W or RW. @@ -1320,6 +1399,8 @@ enum { DRM_IOCTL_PANTHOR(WR, BO_SYNC, bo_sync), DRM_IOCTL_PANTHOR_BO_QUERY_INFO = DRM_IOCTL_PANTHOR(WR, BO_QUERY_INFO, bo_query_info), + DRM_IOCTL_PANTHOR_PROTM_INIT = + DRM_IOCTL_PANTHOR(WR, PROTM_INIT, protm_init), }; #if defined(__cplusplus) -- 2.43.0
