// SPDX-License-Identifier: GPL-2.0 or MIT /* Copyright 2018 Marty E. Plummer <[email protected]> */ /* Copyright 2019 Linaro, Ltd., Rob Herring <[email protected]> */ /* Copyright 2019 Collabora ltd. */ #include <linux/list.h> #include <linux/module.h> #include <linux/of_platform.h> #include <linux/pagemap.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <drm/drm_debugfs.h> #include <drm/drm_drv.h> #include <drm/drm_exec.h> #include <drm/drm_ioctl.h> #include <drm/drm_syncobj.h> #include <drm/drm_utils.h> #include <drm/gpu_scheduler.h> #include <drm/panthor_drm.h> #include "panthor_device.h" #include "panthor_fw.h" #include "panthor_gem.h" #include "panthor_gpu.h" #include "panthor_heap.h" #include "panthor_mmu.h" #include "panthor_regs.h" #include "panthor_sched.h" /** * DOC: user <-> kernel object copy helpers. */ /** * panthor_set_uobj() - Copy kernel object to user object. * @usr_ptr: Users pointer. * @usr_size: Size of the user object. * @min_size: Minimum size for this object. * @kern_size: Size of the kernel object. * @in: Address of the kernel object to copy. * * Helper automating kernel -> user object copies. * * Don't use this function directly, use PANTHOR_UOBJ_SET() instead. * * Return: 0 on success, a negative error code otherwise. */ static int panthor_set_uobj(u64 usr_ptr, u32 usr_size, u32 min_size, u32 kern_size, const void *in) { … } /** * panthor_get_uobj_array() - Copy a user object array into a kernel accessible object array. * @in: The object array to copy. * @min_stride: Minimum array stride. * @obj_size: Kernel object size. * * Helper automating user -> kernel object copies. * * Don't use this function directly, use PANTHOR_UOBJ_GET_ARRAY() instead. * * Return: newly allocated object array or an ERR_PTR on error. */ static void * panthor_get_uobj_array(const struct drm_panthor_obj_array *in, u32 min_stride, u32 obj_size) { … } /** * PANTHOR_UOBJ_MIN_SIZE_INTERNAL() - Get the minimum user object size * @_typename: Object type. * @_last_mandatory_field: Last mandatory field. * * Get the minimum user object size based on the last mandatory field name, * A.K.A, the name of the last field of the structure at the time this * structure was added to the uAPI. * * Don't use directly, use PANTHOR_UOBJ_DECL() instead. */ #define PANTHOR_UOBJ_MIN_SIZE_INTERNAL(_typename, _last_mandatory_field) … /** * PANTHOR_UOBJ_DECL() - Declare a new uAPI object whose subject to * evolutions. * @_typename: Object type. * @_last_mandatory_field: Last mandatory field. * * Should be used to extend the PANTHOR_UOBJ_MIN_SIZE() list. */ #define PANTHOR_UOBJ_DECL(_typename, _last_mandatory_field) … /** * PANTHOR_UOBJ_MIN_SIZE() - Get the minimum size of a given uAPI object * @_obj_name: Object to get the minimum size of. * * Don't use this macro directly, it's automatically called by * PANTHOR_UOBJ_{SET,GET_ARRAY}(). */ #define PANTHOR_UOBJ_MIN_SIZE(_obj_name) … /** * PANTHOR_UOBJ_SET() - Copy a kernel object to a user object. * @_dest_usr_ptr: User pointer to copy to. * @_usr_size: Size of the user object. * @_src_obj: Kernel object to copy (not a pointer). * * Return: 0 on success, a negative error code otherwise. */ #define PANTHOR_UOBJ_SET(_dest_usr_ptr, _usr_size, _src_obj) … /** * PANTHOR_UOBJ_GET_ARRAY() - Copy a user object array to a kernel accessible * object array. * @_dest_array: Local variable that will hold the newly allocated kernel * object array. * @_uobj_array: The drm_panthor_obj_array object describing the user object * array. * * Return: 0 on success, a negative error code otherwise. */ #define PANTHOR_UOBJ_GET_ARRAY(_dest_array, _uobj_array) … /** * struct panthor_sync_signal - Represent a synchronization object point to attach * our job fence to. * * This structure is here to keep track of fences that are currently bound to * a specific syncobj point. * * At the beginning of a job submission, the fence * is retrieved from the syncobj itself, and can be NULL if no fence was attached * to this point. * * At the end, it points to the fence of the last job that had a * %DRM_PANTHOR_SYNC_OP_SIGNAL on this syncobj. * * With jobs being submitted in batches, the fence might change several times during * the process, allowing one job to wait on a job that's part of the same submission * but appears earlier in the drm_panthor_group_submit::queue_submits array. */ struct panthor_sync_signal { … }; /** * struct panthor_job_ctx - Job context */ struct panthor_job_ctx { … }; /** * struct panthor_submit_ctx - Submission context * * Anything that's related to a submission (%DRM_IOCTL_PANTHOR_VM_BIND or * %DRM_IOCTL_PANTHOR_GROUP_SUBMIT) is kept here, so we can automate the * initialization and cleanup steps. */ struct panthor_submit_ctx { … }; #define PANTHOR_SYNC_OP_FLAGS_MASK … static bool sync_op_is_signal(const struct drm_panthor_sync_op *sync_op) { … } static bool sync_op_is_wait(const struct drm_panthor_sync_op *sync_op) { … } /** * panthor_check_sync_op() - Check drm_panthor_sync_op fields * @sync_op: The sync operation to check. * * Return: 0 on success, -EINVAL otherwise. */ static int panthor_check_sync_op(const struct drm_panthor_sync_op *sync_op) { … } /** * panthor_sync_signal_free() - Release resources and free a panthor_sync_signal object * @sig_sync: Signal object to free. */ static void panthor_sync_signal_free(struct panthor_sync_signal *sig_sync) { … } /** * panthor_submit_ctx_add_sync_signal() - Add a signal operation to a submit context * @ctx: Context to add the signal operation to. * @handle: Syncobj handle. * @point: Syncobj point. * * Return: 0 on success, otherwise negative error value. */ static int panthor_submit_ctx_add_sync_signal(struct panthor_submit_ctx *ctx, u32 handle, u64 point) { … } /** * panthor_submit_ctx_search_sync_signal() - Search an existing signal operation in a * submit context. * @ctx: Context to search the signal operation in. * @handle: Syncobj handle. * @point: Syncobj point. * * Return: A valid panthor_sync_signal object if found, NULL otherwise. */ static struct panthor_sync_signal * panthor_submit_ctx_search_sync_signal(struct panthor_submit_ctx *ctx, u32 handle, u64 point) { … } /** * panthor_submit_ctx_add_job() - Add a job to a submit context * @ctx: Context to search the signal operation in. * @idx: Index of the job in the context. * @job: Job to add. * @syncs: Sync operations provided by userspace. * * Return: 0 on success, a negative error code otherwise. */ static int panthor_submit_ctx_add_job(struct panthor_submit_ctx *ctx, u32 idx, struct drm_sched_job *job, const struct drm_panthor_obj_array *syncs) { … } /** * panthor_submit_ctx_get_sync_signal() - Search signal operation and add one if none was found. * @ctx: Context to search the signal operation in. * @handle: Syncobj handle. * @point: Syncobj point. * * Return: 0 on success, a negative error code otherwise. */ static int panthor_submit_ctx_get_sync_signal(struct panthor_submit_ctx *ctx, u32 handle, u64 point) { … } /** * panthor_submit_ctx_update_job_sync_signal_fences() - Update fences * on the signal operations specified by a job. * @ctx: Context to search the signal operation in. * @job_idx: Index of the job to operate on. * * Return: 0 on success, a negative error code otherwise. */ static int panthor_submit_ctx_update_job_sync_signal_fences(struct panthor_submit_ctx *ctx, u32 job_idx) { … } /** * panthor_submit_ctx_collect_job_signal_ops() - Iterate over all job signal operations * and add them to the context. * @ctx: Context to search the signal operation in. * @job_idx: Index of the job to operate on. * * Return: 0 on success, a negative error code otherwise. */ static int panthor_submit_ctx_collect_job_signal_ops(struct panthor_submit_ctx *ctx, u32 job_idx) { … } /** * panthor_submit_ctx_push_fences() - Iterate over the signal array, and for each entry, push * the currently assigned fence to the associated syncobj. * @ctx: Context to push fences on. * * This is the last step of a submission procedure, and is done once we know the submission * is effective and job fences are guaranteed to be signaled in finite time. */ static void panthor_submit_ctx_push_fences(struct panthor_submit_ctx *ctx) { … } /** * panthor_submit_ctx_add_sync_deps_to_job() - Add sync wait operations as * job dependencies. * @ctx: Submit context. * @job_idx: Index of the job to operate on. * * Return: 0 on success, a negative error code otherwise. */ static int panthor_submit_ctx_add_sync_deps_to_job(struct panthor_submit_ctx *ctx, u32 job_idx) { … } /** * panthor_submit_ctx_collect_jobs_signal_ops() - Collect all signal operations * and add them to the submit context. * @ctx: Submit context. * * Return: 0 on success, a negative error code otherwise. */ static int panthor_submit_ctx_collect_jobs_signal_ops(struct panthor_submit_ctx *ctx) { … } /** * panthor_submit_ctx_add_deps_and_arm_jobs() - Add jobs dependencies and arm jobs * @ctx: Submit context. * * Must be called after the resv preparation has been taken care of. * * Return: 0 on success, a negative error code otherwise. */ static int panthor_submit_ctx_add_deps_and_arm_jobs(struct panthor_submit_ctx *ctx) { … } /** * panthor_submit_ctx_push_jobs() - Push jobs to their scheduling entities. * @ctx: Submit context. * @upd_resvs: Callback used to update reservation objects that were previously * preapred. */ static void panthor_submit_ctx_push_jobs(struct panthor_submit_ctx *ctx, void (*upd_resvs)(struct drm_exec *, struct drm_sched_job *)) { … } /** * panthor_submit_ctx_init() - Initializes a submission context * @ctx: Submit context to initialize. * @file: drm_file this submission happens on. * @job_count: Number of jobs that will be submitted. * * Return: 0 on success, a negative error code otherwise. */ static int panthor_submit_ctx_init(struct panthor_submit_ctx *ctx, struct drm_file *file, u32 job_count) { … } /** * panthor_submit_ctx_cleanup() - Cleanup a submission context * @ctx: Submit context to cleanup. * @job_put: Job put callback. */ static void panthor_submit_ctx_cleanup(struct panthor_submit_ctx *ctx, void (*job_put)(struct drm_sched_job *)) { … } static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct drm_file *file) { … } #define PANTHOR_VM_CREATE_FLAGS … static int panthor_ioctl_vm_create(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_ioctl_vm_destroy(struct drm_device *ddev, void *data, struct drm_file *file) { … } #define PANTHOR_BO_FLAGS … static int panthor_ioctl_bo_create(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_ioctl_bo_mmap_offset(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_ioctl_group_submit(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_ioctl_group_destroy(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_ioctl_group_create(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_ioctl_group_get_state(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_ioctl_tiler_heap_create(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_ioctl_tiler_heap_destroy(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_ioctl_vm_bind_async(struct drm_device *ddev, struct drm_panthor_vm_bind *args, struct drm_file *file) { … } static int panthor_ioctl_vm_bind_sync(struct drm_device *ddev, struct drm_panthor_vm_bind *args, struct drm_file *file) { … } #define PANTHOR_VM_BIND_FLAGS … static int panthor_ioctl_vm_bind(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_ioctl_vm_get_state(struct drm_device *ddev, void *data, struct drm_file *file) { … } static int panthor_open(struct drm_device *ddev, struct drm_file *file) { … } static void panthor_postclose(struct drm_device *ddev, struct drm_file *file) { … } static const struct drm_ioctl_desc panthor_drm_driver_ioctls[] = …; static int panthor_mmap(struct file *filp, struct vm_area_struct *vma) { … } static const struct file_operations panthor_drm_driver_fops = …; #ifdef CONFIG_DEBUG_FS static void panthor_debugfs_init(struct drm_minor *minor) { … } #endif /* * PanCSF driver version: * - 1.0 - initial interface */ static const struct drm_driver panthor_drm_driver = …; static int panthor_probe(struct platform_device *pdev) { … } static void panthor_remove(struct platform_device *pdev) { … } static const struct of_device_id dt_match[] = …; MODULE_DEVICE_TABLE(of, dt_match); static DEFINE_RUNTIME_DEV_PM_OPS(panthor_pm_ops, panthor_device_suspend, panthor_device_resume, NULL); static struct platform_driver panthor_driver = …; /* * Workqueue used to cleanup stuff. * * We create a dedicated workqueue so we can drain on unplug and * make sure all resources are freed before the module is unloaded. */ struct workqueue_struct *panthor_cleanup_wq; static int __init panthor_init(void) { … } module_init(…) …; static void __exit panthor_exit(void) { … } module_exit(panthor_exit); MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;