The IOCTL interface is only used for interfacing the GPU parts of the driver. In preparation to disabling GPU functionality split MSM IOCTLs to a separate source file.
Signed-off-by: Dmitry Baryshkov <dmitry.barysh...@oss.qualcomm.com> --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/msm_drv.c | 489 +--------------------------------------- drivers/gpu/drm/msm/msm_ioctl.c | 484 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_ioctl.h | 37 +++ 4 files changed, 523 insertions(+), 488 deletions(-) diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index d7876c154b0aa2cb0164c4b1fb7900b1a42db46b..0ac977a6ed01d91111d706995f341ced29f5ca8d 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -119,6 +119,7 @@ msm-y += \ msm_gpu.o \ msm_gpu_devfreq.o \ msm_io_utils.o \ + msm_ioctl.o \ msm_iommu.o \ msm_perf.o \ msm_rd.o \ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 06ab78e1a2c583352c08a62e6cf250bacde9b75b..ba984cc71d1d3aa341e0f4532b7093adcd25d3b0 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -8,8 +8,6 @@ #include <linux/dma-mapping.h> #include <linux/fault-inject.h> #include <linux/debugfs.h> -#include <linux/of_address.h> -#include <linux/uaccess.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -18,8 +16,8 @@ #include "msm_drv.h" #include "msm_debugfs.h" -#include "msm_gem.h" #include "msm_gpu.h" +#include "msm_ioctl.h" #include "msm_kms.h" /* @@ -296,491 +294,6 @@ static void msm_postclose(struct drm_device *dev, struct drm_file *file) context_close(ctx); } -/* - * DRM ioctls: - */ - -static int msm_ioctl_get_param(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct msm_drm_private *priv = dev->dev_private; - struct drm_msm_param *args = data; - struct msm_gpu *gpu; - - /* for now, we just have 3d pipe.. eventually this would need to - * be more clever to dispatch to appropriate gpu module: - */ - if ((args->pipe != MSM_PIPE_3D0) || (args->pad != 0)) - return -EINVAL; - - gpu = priv->gpu; - - if (!gpu) - return -ENXIO; - - return gpu->funcs->get_param(gpu, file->driver_priv, - args->param, &args->value, &args->len); -} - -static int msm_ioctl_set_param(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct msm_drm_private *priv = dev->dev_private; - struct drm_msm_param *args = data; - struct msm_gpu *gpu; - - if ((args->pipe != MSM_PIPE_3D0) || (args->pad != 0)) - return -EINVAL; - - gpu = priv->gpu; - - if (!gpu) - return -ENXIO; - - return gpu->funcs->set_param(gpu, file->driver_priv, - args->param, args->value, args->len); -} - -static int msm_ioctl_gem_new(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_msm_gem_new *args = data; - uint32_t flags = args->flags; - - if (args->flags & ~MSM_BO_FLAGS) { - DRM_ERROR("invalid flags: %08x\n", args->flags); - return -EINVAL; - } - - /* - * Uncached CPU mappings are deprecated, as of: - * - * 9ef364432db4 ("drm/msm: deprecate MSM_BO_UNCACHED (map as writecombine instead)") - * - * So promote them to WC. - */ - if (flags & MSM_BO_UNCACHED) { - flags &= ~MSM_BO_CACHED; - flags |= MSM_BO_WC; - } - - if (should_fail(&fail_gem_alloc, args->size)) - return -ENOMEM; - - return msm_gem_new_handle(dev, file, args->size, - args->flags, &args->handle, NULL); -} - -static inline ktime_t to_ktime(struct drm_msm_timespec timeout) -{ - return ktime_set(timeout.tv_sec, timeout.tv_nsec); -} - -static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_msm_gem_cpu_prep *args = data; - struct drm_gem_object *obj; - ktime_t timeout = to_ktime(args->timeout); - int ret; - - if (args->op & ~MSM_PREP_FLAGS) { - DRM_ERROR("invalid op: %08x\n", args->op); - return -EINVAL; - } - - obj = drm_gem_object_lookup(file, args->handle); - if (!obj) - return -ENOENT; - - ret = msm_gem_cpu_prep(obj, args->op, &timeout); - - drm_gem_object_put(obj); - - return ret; -} - -static int msm_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_msm_gem_cpu_fini *args = data; - struct drm_gem_object *obj; - int ret; - - obj = drm_gem_object_lookup(file, args->handle); - if (!obj) - return -ENOENT; - - ret = msm_gem_cpu_fini(obj); - - drm_gem_object_put(obj); - - return ret; -} - -static int msm_ioctl_gem_info_iova(struct drm_device *dev, - struct drm_file *file, struct drm_gem_object *obj, - uint64_t *iova) -{ - struct msm_drm_private *priv = dev->dev_private; - struct msm_context *ctx = file->driver_priv; - - if (!priv->gpu) - return -EINVAL; - - if (msm_context_is_vmbind(ctx)) - return UERR(EINVAL, dev, "VM_BIND is enabled"); - - if (should_fail(&fail_gem_iova, obj->size)) - return -ENOMEM; - - /* - * Don't pin the memory here - just get an address so that userspace can - * be productive - */ - return msm_gem_get_iova(obj, msm_context_vm(dev, ctx), iova); -} - -static int msm_ioctl_gem_info_set_iova(struct drm_device *dev, - struct drm_file *file, struct drm_gem_object *obj, - uint64_t iova) -{ - struct msm_drm_private *priv = dev->dev_private; - struct msm_context *ctx = file->driver_priv; - struct drm_gpuvm *vm = msm_context_vm(dev, ctx); - - if (!priv->gpu) - return -EINVAL; - - if (msm_context_is_vmbind(ctx)) - return UERR(EINVAL, dev, "VM_BIND is enabled"); - - /* Only supported if per-process address space is supported: */ - if (priv->gpu->vm == vm) - return UERR(EOPNOTSUPP, dev, "requires per-process pgtables"); - - if (should_fail(&fail_gem_iova, obj->size)) - return -ENOMEM; - - return msm_gem_set_iova(obj, vm, iova); -} - -static int msm_ioctl_gem_info_set_metadata(struct drm_gem_object *obj, - __user void *metadata, - u32 metadata_size) -{ - struct msm_gem_object *msm_obj = to_msm_bo(obj); - void *new_metadata; - void *buf; - int ret; - - /* Impose a moderate upper bound on metadata size: */ - if (metadata_size > 128) { - return -EOVERFLOW; - } - - /* Use a temporary buf to keep copy_from_user() outside of gem obj lock: */ - buf = memdup_user(metadata, metadata_size); - if (IS_ERR(buf)) - return PTR_ERR(buf); - - ret = msm_gem_lock_interruptible(obj); - if (ret) - goto out; - - new_metadata = - krealloc(msm_obj->metadata, metadata_size, GFP_KERNEL); - if (!new_metadata) { - ret = -ENOMEM; - goto out; - } - - msm_obj->metadata = new_metadata; - msm_obj->metadata_size = metadata_size; - memcpy(msm_obj->metadata, buf, metadata_size); - - msm_gem_unlock(obj); - -out: - kfree(buf); - - return ret; -} - -static int msm_ioctl_gem_info_get_metadata(struct drm_gem_object *obj, - __user void *metadata, - u32 *metadata_size) -{ - struct msm_gem_object *msm_obj = to_msm_bo(obj); - void *buf; - int ret, len; - - if (!metadata) { - /* - * Querying the size is inherently racey, but - * EXT_external_objects expects the app to confirm - * via device and driver UUIDs that the exporter and - * importer versions match. All we can do from the - * kernel side is check the length under obj lock - * when userspace tries to retrieve the metadata - */ - *metadata_size = msm_obj->metadata_size; - return 0; - } - - ret = msm_gem_lock_interruptible(obj); - if (ret) - return ret; - - /* Avoid copy_to_user() under gem obj lock: */ - len = msm_obj->metadata_size; - buf = kmemdup(msm_obj->metadata, len, GFP_KERNEL); - - msm_gem_unlock(obj); - - if (*metadata_size < len) { - ret = -ETOOSMALL; - } else if (copy_to_user(metadata, buf, len)) { - ret = -EFAULT; - } else { - *metadata_size = len; - } - - kfree(buf); - - return 0; -} - -static int msm_ioctl_gem_info(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_msm_gem_info *args = data; - struct drm_gem_object *obj; - struct msm_gem_object *msm_obj; - int i, ret = 0; - - if (args->pad) - return -EINVAL; - - switch (args->info) { - case MSM_INFO_GET_OFFSET: - case MSM_INFO_GET_IOVA: - case MSM_INFO_SET_IOVA: - case MSM_INFO_GET_FLAGS: - /* value returned as immediate, not pointer, so len==0: */ - if (args->len) - return -EINVAL; - break; - case MSM_INFO_SET_NAME: - case MSM_INFO_GET_NAME: - case MSM_INFO_SET_METADATA: - case MSM_INFO_GET_METADATA: - break; - default: - return -EINVAL; - } - - obj = drm_gem_object_lookup(file, args->handle); - if (!obj) - return -ENOENT; - - msm_obj = to_msm_bo(obj); - - switch (args->info) { - case MSM_INFO_GET_OFFSET: - args->value = msm_gem_mmap_offset(obj); - break; - case MSM_INFO_GET_IOVA: - ret = msm_ioctl_gem_info_iova(dev, file, obj, &args->value); - break; - case MSM_INFO_SET_IOVA: - ret = msm_ioctl_gem_info_set_iova(dev, file, obj, args->value); - break; - case MSM_INFO_GET_FLAGS: - if (drm_gem_is_imported(obj)) { - ret = -EINVAL; - break; - } - /* Hide internal kernel-only flags: */ - args->value = to_msm_bo(obj)->flags & MSM_BO_FLAGS; - ret = 0; - break; - case MSM_INFO_SET_NAME: - /* length check should leave room for terminating null: */ - if (args->len >= sizeof(msm_obj->name)) { - ret = -EINVAL; - break; - } - if (copy_from_user(msm_obj->name, u64_to_user_ptr(args->value), - args->len)) { - msm_obj->name[0] = '\0'; - ret = -EFAULT; - break; - } - msm_obj->name[args->len] = '\0'; - for (i = 0; i < args->len; i++) { - if (!isprint(msm_obj->name[i])) { - msm_obj->name[i] = '\0'; - break; - } - } - break; - case MSM_INFO_GET_NAME: - if (args->value && (args->len < strlen(msm_obj->name))) { - ret = -ETOOSMALL; - break; - } - args->len = strlen(msm_obj->name); - if (args->value) { - if (copy_to_user(u64_to_user_ptr(args->value), - msm_obj->name, args->len)) - ret = -EFAULT; - } - break; - case MSM_INFO_SET_METADATA: - ret = msm_ioctl_gem_info_set_metadata( - obj, u64_to_user_ptr(args->value), args->len); - break; - case MSM_INFO_GET_METADATA: - ret = msm_ioctl_gem_info_get_metadata( - obj, u64_to_user_ptr(args->value), &args->len); - break; - } - - drm_gem_object_put(obj); - - return ret; -} - -static int wait_fence(struct msm_gpu_submitqueue *queue, uint32_t fence_id, - ktime_t timeout, uint32_t flags) -{ - struct dma_fence *fence; - int ret; - - if (fence_after(fence_id, queue->last_fence)) { - DRM_ERROR_RATELIMITED("waiting on invalid fence: %u (of %u)\n", - fence_id, queue->last_fence); - return -EINVAL; - } - - /* - * Map submitqueue scoped "seqno" (which is actually an idr key) - * back to underlying dma-fence - * - * The fence is removed from the fence_idr when the submit is - * retired, so if the fence is not found it means there is nothing - * to wait for - */ - spin_lock(&queue->idr_lock); - fence = idr_find(&queue->fence_idr, fence_id); - if (fence) - fence = dma_fence_get_rcu(fence); - spin_unlock(&queue->idr_lock); - - if (!fence) - return 0; - - if (flags & MSM_WAIT_FENCE_BOOST) - dma_fence_set_deadline(fence, ktime_get()); - - ret = dma_fence_wait_timeout(fence, true, timeout_to_jiffies(&timeout)); - if (ret == 0) { - ret = -ETIMEDOUT; - } else if (ret != -ERESTARTSYS) { - ret = 0; - } - - dma_fence_put(fence); - - return ret; -} - -static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct msm_drm_private *priv = dev->dev_private; - struct drm_msm_wait_fence *args = data; - struct msm_gpu_submitqueue *queue; - int ret; - - if (args->flags & ~MSM_WAIT_FENCE_FLAGS) { - DRM_ERROR("invalid flags: %08x\n", args->flags); - return -EINVAL; - } - - if (!priv->gpu) - return 0; - - queue = msm_submitqueue_get(file->driver_priv, args->queueid); - if (!queue) - return -ENOENT; - - ret = wait_fence(queue, args->fence, to_ktime(args->timeout), args->flags); - - msm_submitqueue_put(queue); - - return ret; -} - -static int msm_ioctl_gem_madvise(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_msm_gem_madvise *args = data; - struct drm_gem_object *obj; - int ret; - - switch (args->madv) { - case MSM_MADV_DONTNEED: - case MSM_MADV_WILLNEED: - break; - default: - return -EINVAL; - } - - obj = drm_gem_object_lookup(file, args->handle); - if (!obj) { - return -ENOENT; - } - - ret = msm_gem_madvise(obj, args->madv); - if (ret >= 0) { - args->retained = ret; - ret = 0; - } - - drm_gem_object_put(obj); - - return ret; -} - - -static int msm_ioctl_submitqueue_new(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_msm_submitqueue *args = data; - - if (args->flags & ~MSM_SUBMITQUEUE_FLAGS) - return -EINVAL; - - return msm_submitqueue_create(dev, file->driver_priv, args->prio, - args->flags, &args->id); -} - -static int msm_ioctl_submitqueue_query(struct drm_device *dev, void *data, - struct drm_file *file) -{ - return msm_submitqueue_query(dev, file->driver_priv, data); -} - -static int msm_ioctl_submitqueue_close(struct drm_device *dev, void *data, - struct drm_file *file) -{ - u32 id = *(u32 *) data; - - return msm_submitqueue_remove(file->driver_priv, id); -} - static const struct drm_ioctl_desc msm_ioctls[] = { DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(MSM_SET_PARAM, msm_ioctl_set_param, DRM_RENDER_ALLOW), diff --git a/drivers/gpu/drm/msm/msm_ioctl.c b/drivers/gpu/drm/msm/msm_ioctl.c new file mode 100644 index 0000000000000000000000000000000000000000..837be6849684fa72887cb7d709489d54e01c1a5c --- /dev/null +++ b/drivers/gpu/drm/msm/msm_ioctl.c @@ -0,0 +1,484 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdcl...@gmail.com> + */ + +#include <linux/dma-fence.h> +#include <linux/fault-inject.h> +#include <linux/ktime.h> +#include <linux/uaccess.h> + +#include <drm/drm_drv.h> +#include <drm/drm_file.h> +#include <drm/drm_ioctl.h> + +#include "msm_drv.h" +#include "msm_gpu.h" +#include "msm_ioctl.h" + +/* + * DRM ioctls: + */ + +static inline ktime_t to_ktime(struct drm_msm_timespec timeout) +{ + return ktime_set(timeout.tv_sec, timeout.tv_nsec); +} + +int msm_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct msm_drm_private *priv = dev->dev_private; + struct drm_msm_param *args = data; + struct msm_gpu *gpu; + + /* for now, we just have 3d pipe.. eventually this would need to + * be more clever to dispatch to appropriate gpu module: + */ + if ((args->pipe != MSM_PIPE_3D0) || (args->pad != 0)) + return -EINVAL; + + gpu = priv->gpu; + + if (!gpu) + return -ENXIO; + + return gpu->funcs->get_param(gpu, file->driver_priv, + args->param, &args->value, &args->len); +} + +int msm_ioctl_set_param(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct msm_drm_private *priv = dev->dev_private; + struct drm_msm_param *args = data; + struct msm_gpu *gpu; + + if ((args->pipe != MSM_PIPE_3D0) || (args->pad != 0)) + return -EINVAL; + + gpu = priv->gpu; + + if (!gpu) + return -ENXIO; + + return gpu->funcs->set_param(gpu, file->driver_priv, + args->param, args->value, args->len); +} + +int msm_ioctl_gem_new(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct drm_msm_gem_new *args = data; + uint32_t flags = args->flags; + + if (args->flags & ~MSM_BO_FLAGS) { + DRM_ERROR("invalid flags: %08x\n", args->flags); + return -EINVAL; + } + + /* + * Uncached CPU mappings are deprecated, as of: + * + * 9ef364432db4 ("drm/msm: deprecate MSM_BO_UNCACHED (map as writecombine instead)") + * + * So promote them to WC. + */ + if (flags & MSM_BO_UNCACHED) { + flags &= ~MSM_BO_CACHED; + flags |= MSM_BO_WC; + } + + if (should_fail(&fail_gem_alloc, args->size)) + return -ENOMEM; + + return msm_gem_new_handle(dev, file, args->size, + args->flags, &args->handle, NULL); +} + +int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct drm_msm_gem_cpu_prep *args = data; + struct drm_gem_object *obj; + ktime_t timeout = to_ktime(args->timeout); + int ret; + + if (args->op & ~MSM_PREP_FLAGS) { + DRM_ERROR("invalid op: %08x\n", args->op); + return -EINVAL; + } + + obj = drm_gem_object_lookup(file, args->handle); + if (!obj) + return -ENOENT; + + ret = msm_gem_cpu_prep(obj, args->op, &timeout); + + drm_gem_object_put(obj); + + return ret; +} + +int msm_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct drm_msm_gem_cpu_fini *args = data; + struct drm_gem_object *obj; + int ret; + + obj = drm_gem_object_lookup(file, args->handle); + if (!obj) + return -ENOENT; + + ret = msm_gem_cpu_fini(obj); + + drm_gem_object_put(obj); + + return ret; +} + +int msm_ioctl_gem_info_iova(struct drm_device *dev, struct drm_file *file, + struct drm_gem_object *obj, uint64_t *iova) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_context *ctx = file->driver_priv; + + if (!priv->gpu) + return -EINVAL; + + if (msm_context_is_vmbind(ctx)) + return UERR(EINVAL, dev, "VM_BIND is enabled"); + + if (should_fail(&fail_gem_iova, obj->size)) + return -ENOMEM; + + /* + * Don't pin the memory here - just get an address so that userspace can + * be productive + */ + return msm_gem_get_iova(obj, msm_context_vm(dev, ctx), iova); +} + +int msm_ioctl_gem_info_set_iova(struct drm_device *dev, struct drm_file *file, + struct drm_gem_object *obj, uint64_t iova) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_context *ctx = file->driver_priv; + struct drm_gpuvm *vm = msm_context_vm(dev, ctx); + + if (!priv->gpu) + return -EINVAL; + + if (msm_context_is_vmbind(ctx)) + return UERR(EINVAL, dev, "VM_BIND is enabled"); + + /* Only supported if per-process address space is supported: */ + if (priv->gpu->vm == vm) + return UERR(EOPNOTSUPP, dev, "requires per-process pgtables"); + + if (should_fail(&fail_gem_iova, obj->size)) + return -ENOMEM; + + return msm_gem_set_iova(obj, vm, iova); +} + +int msm_ioctl_gem_info_set_metadata(struct drm_gem_object *obj, + __user void *metadata, u32 metadata_size) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + void *new_metadata; + void *buf; + int ret; + + /* Impose a moderate upper bound on metadata size: */ + if (metadata_size > 128) + return -EOVERFLOW; + + /* Use a temporary buf to keep copy_from_user() outside of gem obj lock: */ + buf = memdup_user(metadata, metadata_size); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + ret = msm_gem_lock_interruptible(obj); + if (ret) + goto out; + + new_metadata = + krealloc(msm_obj->metadata, metadata_size, GFP_KERNEL); + if (!new_metadata) { + ret = -ENOMEM; + goto out; + } + + msm_obj->metadata = new_metadata; + msm_obj->metadata_size = metadata_size; + memcpy(msm_obj->metadata, buf, metadata_size); + + msm_gem_unlock(obj); + +out: + kfree(buf); + + return ret; +} + +int msm_ioctl_gem_info_get_metadata(struct drm_gem_object *obj, + __user void *metadata, u32 *metadata_size) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + void *buf; + int ret, len; + + if (!metadata) { + /* + * Querying the size is inherently racey, but + * EXT_external_objects expects the app to confirm + * via device and driver UUIDs that the exporter and + * importer versions match. All we can do from the + * kernel side is check the length under obj lock + * when userspace tries to retrieve the metadata + */ + *metadata_size = msm_obj->metadata_size; + return 0; + } + + ret = msm_gem_lock_interruptible(obj); + if (ret) + return ret; + + /* Avoid copy_to_user() under gem obj lock: */ + len = msm_obj->metadata_size; + buf = kmemdup(msm_obj->metadata, len, GFP_KERNEL); + + msm_gem_unlock(obj); + + if (*metadata_size < len) + ret = -ETOOSMALL; + else if (copy_to_user(metadata, buf, len)) + ret = -EFAULT; + else + *metadata_size = len; + + kfree(buf); + + return 0; +} + +int msm_ioctl_gem_info(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct drm_msm_gem_info *args = data; + struct drm_gem_object *obj; + struct msm_gem_object *msm_obj; + int i, ret = 0; + + if (args->pad) + return -EINVAL; + + switch (args->info) { + case MSM_INFO_GET_OFFSET: + case MSM_INFO_GET_IOVA: + case MSM_INFO_SET_IOVA: + case MSM_INFO_GET_FLAGS: + /* value returned as immediate, not pointer, so len==0: */ + if (args->len) + return -EINVAL; + break; + case MSM_INFO_SET_NAME: + case MSM_INFO_GET_NAME: + case MSM_INFO_SET_METADATA: + case MSM_INFO_GET_METADATA: + break; + default: + return -EINVAL; + } + + obj = drm_gem_object_lookup(file, args->handle); + if (!obj) + return -ENOENT; + + msm_obj = to_msm_bo(obj); + + switch (args->info) { + case MSM_INFO_GET_OFFSET: + args->value = msm_gem_mmap_offset(obj); + break; + case MSM_INFO_GET_IOVA: + ret = msm_ioctl_gem_info_iova(dev, file, obj, &args->value); + break; + case MSM_INFO_SET_IOVA: + ret = msm_ioctl_gem_info_set_iova(dev, file, obj, args->value); + break; + case MSM_INFO_GET_FLAGS: + if (drm_gem_is_imported(obj)) { + ret = -EINVAL; + break; + } + /* Hide internal kernel-only flags: */ + args->value = to_msm_bo(obj)->flags & MSM_BO_FLAGS; + ret = 0; + break; + case MSM_INFO_SET_NAME: + /* length check should leave room for terminating null: */ + if (args->len >= sizeof(msm_obj->name)) { + ret = -EINVAL; + break; + } + if (copy_from_user(msm_obj->name, u64_to_user_ptr(args->value), + args->len)) { + msm_obj->name[0] = '\0'; + ret = -EFAULT; + break; + } + msm_obj->name[args->len] = '\0'; + for (i = 0; i < args->len; i++) { + if (!isprint(msm_obj->name[i])) { + msm_obj->name[i] = '\0'; + break; + } + } + break; + case MSM_INFO_GET_NAME: + if (args->value && (args->len < strlen(msm_obj->name))) { + ret = -ETOOSMALL; + break; + } + args->len = strlen(msm_obj->name); + if (args->value) { + if (copy_to_user(u64_to_user_ptr(args->value), + msm_obj->name, args->len)) + ret = -EFAULT; + } + break; + case MSM_INFO_SET_METADATA: + ret = msm_ioctl_gem_info_set_metadata( + obj, u64_to_user_ptr(args->value), args->len); + break; + case MSM_INFO_GET_METADATA: + ret = msm_ioctl_gem_info_get_metadata( + obj, u64_to_user_ptr(args->value), &args->len); + break; + } + + drm_gem_object_put(obj); + + return ret; +} + +static int wait_fence(struct msm_gpu_submitqueue *queue, uint32_t fence_id, + ktime_t timeout, uint32_t flags) +{ + struct dma_fence *fence; + int ret; + + if (fence_after(fence_id, queue->last_fence)) { + DRM_ERROR_RATELIMITED("waiting on invalid fence: %u (of %u)\n", + fence_id, queue->last_fence); + return -EINVAL; + } + + /* + * Map submitqueue scoped "seqno" (which is actually an idr key) + * back to underlying dma-fence + * + * The fence is removed from the fence_idr when the submit is + * retired, so if the fence is not found it means there is nothing + * to wait for + */ + spin_lock(&queue->idr_lock); + fence = idr_find(&queue->fence_idr, fence_id); + if (fence) + fence = dma_fence_get_rcu(fence); + spin_unlock(&queue->idr_lock); + + if (!fence) + return 0; + + if (flags & MSM_WAIT_FENCE_BOOST) + dma_fence_set_deadline(fence, ktime_get()); + + ret = dma_fence_wait_timeout(fence, true, timeout_to_jiffies(&timeout)); + if (ret == 0) + ret = -ETIMEDOUT; + else if (ret != -ERESTARTSYS) + ret = 0; + + dma_fence_put(fence); + + return ret; +} + +int msm_ioctl_wait_fence(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct msm_drm_private *priv = dev->dev_private; + struct drm_msm_wait_fence *args = data; + struct msm_gpu_submitqueue *queue; + int ret; + + if (args->flags & ~MSM_WAIT_FENCE_FLAGS) { + DRM_ERROR("invalid flags: %08x\n", args->flags); + return -EINVAL; + } + + if (!priv->gpu) + return 0; + + queue = msm_submitqueue_get(file->driver_priv, args->queueid); + if (!queue) + return -ENOENT; + + ret = wait_fence(queue, args->fence, to_ktime(args->timeout), args->flags); + + msm_submitqueue_put(queue); + + return ret; +} + +int msm_ioctl_gem_madvise(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct drm_msm_gem_madvise *args = data; + struct drm_gem_object *obj; + int ret; + + switch (args->madv) { + case MSM_MADV_DONTNEED: + case MSM_MADV_WILLNEED: + break; + default: + return -EINVAL; + } + + obj = drm_gem_object_lookup(file, args->handle); + if (!obj) + return -ENOENT; + + ret = msm_gem_madvise(obj, args->madv); + if (ret >= 0) { + args->retained = ret; + ret = 0; + } + + drm_gem_object_put(obj); + + return ret; +} + +int msm_ioctl_submitqueue_new(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct drm_msm_submitqueue *args = data; + + if (args->flags & ~MSM_SUBMITQUEUE_FLAGS) + return -EINVAL; + + return msm_submitqueue_create(dev, file->driver_priv, args->prio, + args->flags, &args->id); +} + +int msm_ioctl_submitqueue_query(struct drm_device *dev, void *data, struct drm_file *file) +{ + return msm_submitqueue_query(dev, file->driver_priv, data); +} + +int msm_ioctl_submitqueue_close(struct drm_device *dev, void *data, struct drm_file *file) +{ + u32 id = *(u32 *) data; + + return msm_submitqueue_remove(file->driver_priv, id); +} diff --git a/drivers/gpu/drm/msm/msm_ioctl.h b/drivers/gpu/drm/msm/msm_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..5711476a00df4773b12020a37bfb3ceb964c19ee --- /dev/null +++ b/drivers/gpu/drm/msm/msm_ioctl.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdcl...@gmail.com> + */ + +#ifndef __MSM_IOCTLS_H__ +#define __MSM_IOCTLS_H__ + +#include <linux/types.h> + +struct drm_device; +struct drm_file; +struct drm_gem_object; + +int msm_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file); +int msm_ioctl_set_param(struct drm_device *dev, void *data, struct drm_file *file); +int msm_ioctl_gem_new(struct drm_device *dev, void *data, struct drm_file *file); +int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, struct drm_file *file); +int msm_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, struct drm_file *file); +int msm_ioctl_gem_info_iova(struct drm_device *dev, struct drm_file *file, + struct drm_gem_object *obj, uint64_t *iova); +int msm_ioctl_gem_info_set_iova(struct drm_device *dev, struct drm_file *file, + struct drm_gem_object *obj, uint64_t iova); +int msm_ioctl_gem_info_set_metadata(struct drm_gem_object *obj, + __user void *metadata, u32 metadata_size); +int msm_ioctl_gem_info_get_metadata(struct drm_gem_object *obj, + __user void *metadata, u32 *metadata_size); +int msm_ioctl_gem_info(struct drm_device *dev, void *data, struct drm_file *file); +int msm_ioctl_wait_fence(struct drm_device *dev, void *data, struct drm_file *file); +int msm_ioctl_gem_madvise(struct drm_device *dev, void *data, struct drm_file *file); +int msm_ioctl_submitqueue_new(struct drm_device *dev, void *data, struct drm_file *file); +int msm_ioctl_submitqueue_query(struct drm_device *dev, void *data, struct drm_file *file); +int msm_ioctl_submitqueue_close(struct drm_device *dev, void *data, struct drm_file *file); + +#endif -- 2.47.3