aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/zocl/zocl_bo.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/zocl/zocl_bo.c')
-rw-r--r--drivers/gpu/drm/zocl/zocl_bo.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/drivers/gpu/drm/zocl/zocl_bo.c b/drivers/gpu/drm/zocl/zocl_bo.c
new file mode 100644
index 000000000000..123a37842ad4
--- /dev/null
+++ b/drivers/gpu/drm/zocl/zocl_bo.c
@@ -0,0 +1,271 @@
+/*
+ * A GEM style CMA backed memory manager for ZynQ based OpenCL accelerators.
+ *
+ * Copyright (C) 2016 Xilinx, Inc. All rights reserved.
+ *
+ * Authors:
+ * Sonal Santan <sonal.santan@xilinx.com>
+ * Umang Parekh <umang.parekh@xilinx.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/dma-buf.h>
+#include <linux/module.h>
+#include <linux/ramfs.h>
+#include <linux/shmem_fs.h>
+#include "zocl_drv.h"
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <linux/zocl_ioctl.h>
+
+static inline void __user *to_user_ptr(u64 address)
+{
+ return (void __user *)(uintptr_t)address;
+}
+
+void zocl_describe(const struct drm_zocl_bo *obj)
+{
+ size_t size_in_kb = obj->base.base.size / 1024;
+ size_t physical_addr = obj->base.paddr;
+
+ DRM_INFO("%p: H[0x%zxKB] D[0x%zx]\n",
+ obj,
+ size_in_kb,
+ physical_addr);
+}
+
+static struct drm_zocl_bo *zocl_create_bo(struct drm_device *dev,
+ uint64_t unaligned_size)
+{
+ size_t size = PAGE_ALIGN(unaligned_size);
+ struct drm_gem_cma_object *cma_obj;
+
+ DRM_DEBUG("%s:%s:%d: %zd\n", __FILE__, __func__, __LINE__, size);
+
+ if (!size)
+ return ERR_PTR(-EINVAL);
+
+ cma_obj = drm_gem_cma_create(dev, size);
+ if (IS_ERR(cma_obj))
+ return ERR_PTR(-ENOMEM);
+
+ return to_zocl_bo(&cma_obj->base);
+}
+
+int zocl_create_bo_ioctl(struct drm_device *dev,
+ void *data,
+ struct drm_file *filp)
+{
+ int ret;
+ struct drm_zocl_create_bo *args = data;
+ struct drm_zocl_bo *bo;
+
+ if (((args->flags & DRM_ZOCL_BO_FLAGS_COHERENT) == 0) ||
+ ((args->flags & DRM_ZOCL_BO_FLAGS_CMA) == 0))
+ return -EINVAL;
+
+ bo = zocl_create_bo(dev, args->size);
+ bo->flags |= DRM_ZOCL_BO_FLAGS_COHERENT;
+ bo->flags |= DRM_ZOCL_BO_FLAGS_CMA;
+
+ DRM_DEBUG("%s:%s:%d: %p\n", __FILE__, __func__, __LINE__, bo);
+
+ if (IS_ERR(bo)) {
+ DRM_DEBUG("object creation failed\n");
+ return PTR_ERR(bo);
+ }
+ ret = drm_gem_handle_create(filp, &bo->base.base, &args->handle);
+ if (ret) {
+ drm_gem_cma_free_object(&bo->base.base);
+ DRM_DEBUG("handle creation failed\n");
+ return ret;
+ }
+
+ zocl_describe(bo);
+ drm_gem_object_put_unlocked(&bo->base.base);
+
+ return ret;
+}
+
+int zocl_map_bo_ioctl(struct drm_device *dev,
+ void *data,
+ struct drm_file *filp)
+{
+ struct drm_zocl_map_bo *args = data;
+ struct drm_gem_object *gem_obj;
+
+ DRM_DEBUG("%s:%s:%d: %p\n", __FILE__, __func__, __LINE__, data);
+ gem_obj = drm_gem_object_lookup(dev, filp, args->handle);
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
+ return -EINVAL;
+ }
+
+ /* The mmap offset was set up at BO allocation time. */
+ args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
+ zocl_describe(to_zocl_bo(gem_obj));
+ drm_gem_object_put_unlocked(gem_obj);
+
+ return 0;
+}
+
+int zocl_sync_bo_ioctl(struct drm_device *dev,
+ void *data,
+ struct drm_file *filp)
+{
+ const struct drm_zocl_sync_bo *args = data;
+ struct drm_gem_object *gem_obj = drm_gem_object_lookup(dev, filp,
+ args->handle);
+ void *kaddr;
+ int ret = 0;
+
+ DRM_DEBUG("%s:%s:%d: %p\n", __FILE__, __func__, __LINE__, data);
+
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
+ return -EINVAL;
+ }
+
+ if ((args->offset > gem_obj->size) || (args->size > gem_obj->size) ||
+ ((args->offset + args->size) > gem_obj->size)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ kaddr = drm_gem_cma_prime_vmap(gem_obj);
+
+ /* only invalidate the range of addresses requested by the user */
+ kaddr += args->offset;
+
+ if (args->dir == DRM_ZOCL_SYNC_BO_TO_DEVICE)
+ flush_kernel_vmap_range(kaddr, args->size);
+ else if (args->dir == DRM_ZOCL_SYNC_BO_FROM_DEVICE)
+ invalidate_kernel_vmap_range(kaddr, args->size);
+ else
+ ret = -EINVAL;
+
+out:
+ drm_gem_object_put_unlocked(gem_obj);
+
+ return ret;
+}
+
+int zocl_info_bo_ioctl(struct drm_device *dev,
+ void *data,
+ struct drm_file *filp)
+{
+ const struct drm_zocl_bo *bo;
+ struct drm_zocl_info_bo *args = data;
+ struct drm_gem_object *gem_obj = drm_gem_object_lookup(dev, filp,
+ args->handle);
+
+ DRM_DEBUG("%s:%s:%d: %p\n", __FILE__, __func__, __LINE__, data);
+
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
+ return -EINVAL;
+ }
+
+ bo = to_zocl_bo(gem_obj);
+
+ args->size = bo->base.base.size;
+ args->paddr = bo->base.paddr;
+ drm_gem_object_put_unlocked(gem_obj);
+
+ return 0;
+}
+
+int zocl_pwrite_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ const struct drm_zocl_pwrite_bo *args = data;
+ struct drm_gem_object *gem_obj = drm_gem_object_lookup(dev, filp,
+ args->handle);
+ char __user *user_data = to_user_ptr(args->data_ptr);
+ int ret = 0;
+ void *kaddr;
+
+ DRM_DEBUG("%s:%s:%d: %p\n", __FILE__, __func__, __LINE__, data);
+
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
+ return -EINVAL;
+ }
+
+ if ((args->offset > gem_obj->size) || (args->size > gem_obj->size)
+ || ((args->offset + args->size) > gem_obj->size)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (args->size == 0) {
+ ret = 0;
+ goto out;
+ }
+
+ if (!access_ok(user_data, args->size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ kaddr = drm_gem_cma_prime_vmap(gem_obj);
+ kaddr += args->offset;
+
+ ret = copy_from_user(kaddr, user_data, args->size);
+out:
+ drm_gem_object_put_unlocked(gem_obj);
+
+ return ret;
+}
+
+int zocl_pread_bo_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ const struct drm_zocl_pread_bo *args = data;
+ struct drm_gem_object *gem_obj = drm_gem_object_lookup(dev, filp,
+ args->handle);
+ char __user *user_data = to_user_ptr(args->data_ptr);
+ int ret = 0;
+ void *kaddr;
+
+ DRM_DEBUG("%s:%s:%d: %p\n", __FILE__, __func__, __LINE__, data);
+
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
+ return -EINVAL;
+ }
+
+ if ((args->offset > gem_obj->size) || (args->size > gem_obj->size)
+ || ((args->offset + args->size) > gem_obj->size)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (args->size == 0) {
+ ret = 0;
+ goto out;
+ }
+
+ if (!access_ok(user_data, args->size)) {
+ ret = EFAULT;
+ goto out;
+ }
+
+ kaddr = drm_gem_cma_prime_vmap(gem_obj);
+ kaddr += args->offset;
+
+ ret = copy_to_user(user_data, kaddr, args->size);
+
+out:
+ drm_gem_object_put_unlocked(gem_obj);
+
+ return ret;
+}