[PATCH v2 7/7] drm/panthor: Expose protected rendering features
From: Ketil Johnsen
Date: Sun Jul 12 2026 - 09:57:30 EST
From: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxx>
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 <boris.brezillon@xxxxxxxxxxxxx>
Co-developed-by: Ketil Johnsen <ketil.johnsen@xxxxxxx>
Signed-off-by: Ketil Johnsen <ketil.johnsen@xxxxxxx>
---
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