From: Lima Project Developers <dri-devel@lists.freedesktop.org>

Signed-off-by: Qiang Yu <yuq...@gmail.com>
Signed-off-by: Erico Nunes <nunes.er...@gmail.com>
Signed-off-by: Heiko Stuebner <he...@sntech.de>
---
 drivers/gpu/drm/lima/lima_gem.c | 459 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/lima/lima_gem.h |  41 +++
 2 files changed, 500 insertions(+)
 create mode 100644 drivers/gpu/drm/lima/lima_gem.c
 create mode 100644 drivers/gpu/drm/lima/lima_gem.h

diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
new file mode 100644
index 000000000000..1ad3f38ddfde
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_gem.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <drm/drmP.h>
+#include <linux/dma-mapping.h>
+#include <linux/pagemap.h>
+#include <linux/sync_file.h>
+
+#include <drm/lima_drm.h>
+
+#include "lima_drv.h"
+#include "lima_gem.h"
+#include "lima_vm.h"
+#include "lima_object.h"
+
+int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
+                          u32 size, u32 flags, u32 *handle)
+{
+       int err;
+       struct lima_bo *bo;
+       struct lima_device *ldev = to_lima_dev(dev);
+
+       bo = lima_bo_create(ldev, size, flags, ttm_bo_type_device, NULL, NULL);
+       if (IS_ERR(bo))
+               return PTR_ERR(bo);
+
+       err = drm_gem_handle_create(file, &bo->gem, handle);
+
+       /* drop reference from allocate - handle holds it now */
+       drm_gem_object_put_unlocked(&bo->gem);
+
+       return err;
+}
+
+void lima_gem_free_object(struct drm_gem_object *obj)
+{
+       struct lima_bo *bo = to_lima_bo(obj);
+
+       if (!list_empty(&bo->va))
+               dev_err(obj->dev->dev, "lima gem free bo still has va\n");
+
+       lima_bo_unref(bo);
+}
+
+int lima_gem_object_open(struct drm_gem_object *obj, struct drm_file *file)
+{
+       struct lima_bo *bo = to_lima_bo(obj);
+       struct lima_drm_priv *priv = to_lima_drm_priv(file);
+       struct lima_vm *vm = priv->vm;
+       int err;
+
+       err = lima_bo_reserve(bo, true);
+       if (err)
+               return err;
+
+       err = lima_vm_bo_add(vm, bo);
+
+       lima_bo_unreserve(bo);
+       return err;
+}
+
+void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *file)
+{
+       struct lima_bo *bo = to_lima_bo(obj);
+       struct lima_device *dev = to_lima_dev(obj->dev);
+       struct lima_drm_priv *priv = to_lima_drm_priv(file);
+       struct lima_vm *vm = priv->vm;
+
+       LIST_HEAD(list);
+       struct ttm_validate_buffer tv_bo, tv_pd;
+       struct ww_acquire_ctx ticket;
+       int r;
+
+       tv_bo.bo = &bo->tbo;
+       tv_bo.shared = true;
+       list_add(&tv_bo.head, &list);
+
+       tv_pd.bo = &vm->pd->tbo;
+       tv_pd.shared = true;
+       list_add(&tv_pd.head, &list);
+
+       r = ttm_eu_reserve_buffers(&ticket, &list, false, NULL);
+       if (r) {
+               dev_err(dev->dev, "leeking bo va because we "
+                       "fail to reserve bo (%d)\n", r);
+               return;
+       }
+
+       lima_vm_bo_del(vm, bo);
+
+       ttm_eu_backoff_reservation(&ticket, &list);
+}
+
+int lima_gem_mmap_offset(struct drm_file *file, u32 handle, u64 *offset)
+{
+       struct drm_gem_object *obj;
+       struct lima_bo *bo;
+
+       obj = drm_gem_object_lookup(file, handle);
+       if (!obj)
+               return -ENOENT;
+
+       bo = to_lima_bo(obj);
+       *offset = drm_vma_node_offset_addr(&bo->tbo.vma_node);
+
+       drm_gem_object_put_unlocked(obj);
+       return 0;
+}
+
+int lima_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_file *file_priv;
+       struct lima_device *dev;
+
+       if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+               return -EINVAL;
+
+       file_priv = filp->private_data;
+       dev = file_priv->minor->dev->dev_private;
+       if (dev == NULL)
+               return -EINVAL;
+
+       return ttm_bo_mmap(filp, vma, &dev->mman.bdev);
+}
+
+int lima_gem_va_map(struct drm_file *file, u32 handle, u32 flags, u32 va)
+{
+       struct lima_drm_priv *priv = to_lima_drm_priv(file);
+       struct lima_vm *vm = priv->vm;
+       struct drm_gem_object *obj;
+       struct lima_bo *bo;
+       struct lima_device *dev;
+       int err;
+
+       LIST_HEAD(list);
+       struct ttm_validate_buffer tv_bo, tv_pd;
+       struct ww_acquire_ctx ticket;
+
+       if (!PAGE_ALIGNED(va))
+               return -EINVAL;
+
+       obj = drm_gem_object_lookup(file, handle);
+       if (!obj)
+               return -ENOENT;
+
+       bo = to_lima_bo(obj);
+       dev = to_lima_dev(obj->dev);
+
+       /* carefully handle overflow when calculate range */
+       if (va < dev->va_start || dev->va_end - obj->size < va) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       tv_bo.bo = &bo->tbo;
+       tv_bo.shared = true;
+       list_add(&tv_bo.head, &list);
+
+       tv_pd.bo = &vm->pd->tbo;
+       tv_pd.shared = true;
+       list_add(&tv_pd.head, &list);
+
+       err = ttm_eu_reserve_buffers(&ticket, &list, false, NULL);
+       if (err)
+               goto out;
+
+       err = lima_vm_bo_map(vm, bo, va);
+
+       ttm_eu_backoff_reservation(&ticket, &list);
+out:
+       drm_gem_object_put_unlocked(obj);
+       return err;
+}
+
+int lima_gem_va_unmap(struct drm_file *file, u32 handle, u32 va)
+{
+       struct lima_drm_priv *priv = to_lima_drm_priv(file);
+       struct lima_vm *vm = priv->vm;
+       struct drm_gem_object *obj;
+       struct lima_bo *bo;
+       int err;
+
+       LIST_HEAD(list);
+       struct ttm_validate_buffer tv_bo, tv_pd;
+       struct ww_acquire_ctx ticket;
+
+       if (!PAGE_ALIGNED(va))
+               return -EINVAL;
+
+       obj = drm_gem_object_lookup(file, handle);
+       if (!obj)
+               return -ENOENT;
+
+       bo = to_lima_bo(obj);
+
+       tv_bo.bo = &bo->tbo;
+       tv_bo.shared = true;
+       list_add(&tv_bo.head, &list);
+
+       tv_pd.bo = &vm->pd->tbo;
+       tv_pd.shared = true;
+       list_add(&tv_pd.head, &list);
+
+       err = ttm_eu_reserve_buffers(&ticket, &list, false, NULL);
+       if (err)
+               goto out;
+
+       err = lima_vm_bo_unmap(vm, bo, va);
+
+       ttm_eu_backoff_reservation(&ticket, &list);
+out:
+       drm_gem_object_put_unlocked(obj);
+       return err;
+}
+
+static int lima_gem_sync_bo(struct lima_sched_task *task, struct lima_bo *bo,
+                           bool write, bool explicit)
+{
+       int i, err;
+       struct dma_fence *f;
+       u64 context = task->base.s_fence->finished.context;
+
+       if (!write) {
+               err = reservation_object_reserve_shared(bo->tbo.resv);
+               if (err)
+                       return err;
+       }
+
+       /* explicit sync use user passed dep fence */
+       if (explicit)
+               return 0;
+
+       /* implicit sync use bo fence in resv obj */
+       if (write) {
+               struct reservation_object_list *fobj =
+                       reservation_object_get_list(bo->tbo.resv);
+
+               if (fobj && fobj->shared_count > 0) {
+                       for (i = 0; i < fobj->shared_count; i++) {
+                               f = rcu_dereference_protected(
+                                       fobj->shared[i],
+                                       reservation_object_held(bo->tbo.resv));
+                               if (f->context != context) {
+                                       err = lima_sched_task_add_dep(task, f);
+                                       if (err)
+                                               return err;
+                               }
+                       }
+               }
+       }
+
+       f = reservation_object_get_excl(bo->tbo.resv);
+       if (f) {
+               err = lima_sched_task_add_dep(task, f);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int lima_gem_add_deps(struct lima_ctx_mgr *mgr, struct lima_submit 
*submit)
+{
+       int i, err = 0;
+
+       for (i = 0; i < submit->nr_deps; i++) {
+               union drm_lima_gem_submit_dep *dep = submit->deps + i;
+               struct dma_fence *fence;
+
+               if (dep->type == LIMA_SUBMIT_DEP_FENCE) {
+                       fence = lima_ctx_get_native_fence(
+                               mgr, dep->fence.ctx, dep->fence.pipe,
+                               dep->fence.seq);
+                       if (IS_ERR(fence)) {
+                               err = PTR_ERR(fence);
+                               break;
+                       }
+               }
+               else if (dep->type == LIMA_SUBMIT_DEP_SYNC_FD) {
+                       fence = sync_file_get_fence(dep->sync_fd.fd);
+                       if (!fence) {
+                               err = -EINVAL;
+                               break;
+                       }
+               }
+               else {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (fence) {
+                       err = lima_sched_task_add_dep(submit->task, fence);
+                       dma_fence_put(fence);
+                       if (err)
+                               break;
+               }
+       }
+
+       return err;
+}
+
+static int lima_gem_get_sync_fd(struct dma_fence *fence)
+{
+       struct sync_file *sync_file;
+       int fd;
+
+       fd = get_unused_fd_flags(O_CLOEXEC);
+       if (fd < 0)
+               return fd;
+
+       sync_file = sync_file_create(fence);
+       if (!sync_file) {
+               put_unused_fd(fd);
+               return -ENOMEM;
+       }
+
+       fd_install(fd, sync_file->file);
+       return fd;
+}
+
+int lima_gem_submit(struct drm_file *file, struct lima_submit *submit)
+{
+       int i, err = 0;
+       struct lima_drm_priv *priv = to_lima_drm_priv(file);
+       struct lima_vm *vm = priv->vm;
+
+       INIT_LIST_HEAD(&submit->validated);
+       INIT_LIST_HEAD(&submit->duplicates);
+
+       for (i = 0; i < submit->nr_bos; i++) {
+               struct drm_gem_object *obj;
+               struct drm_lima_gem_submit_bo *bo = submit->bos + i;
+               struct ttm_validate_buffer *vb = submit->vbs + i;
+
+               obj = drm_gem_object_lookup(file, bo->handle);
+               if (!obj) {
+                       err = -ENOENT;
+                       goto out0;
+               }
+
+               vb->bo = &to_lima_bo(obj)->tbo;
+               vb->shared = !(bo->flags & LIMA_SUBMIT_BO_WRITE);
+               list_add_tail(&vb->head, &submit->validated);
+       }
+
+       submit->vm_pd_vb.bo = &vm->pd->tbo;
+       submit->vm_pd_vb.shared = true;
+       list_add(&submit->vm_pd_vb.head, &submit->validated);
+
+       err = ttm_eu_reserve_buffers(&submit->ticket, &submit->validated,
+                                    true, &submit->duplicates);
+       if (err)
+               goto out0;
+
+       err = lima_sched_task_init(
+               submit->task, submit->ctx->context + submit->pipe, vm);
+       if (err)
+               goto out1;
+
+       err = lima_gem_add_deps(&priv->ctx_mgr, submit);
+       if (err)
+               goto out2;
+
+       for (i = 0; i < submit->nr_bos; i++) {
+               struct ttm_validate_buffer *vb = submit->vbs + i;
+               struct lima_bo *bo = ttm_to_lima_bo(vb->bo);
+               err = lima_gem_sync_bo(
+                       submit->task, bo, !vb->shared,
+                       submit->flags & LIMA_SUBMIT_FLAG_EXPLICIT_FENCE);
+               if (err)
+                       goto out2;
+       }
+
+       if (submit->flags & LIMA_SUBMIT_FLAG_SYNC_FD_OUT) {
+               int fd = lima_gem_get_sync_fd(
+                       &submit->task->base.s_fence->finished);
+               if (fd < 0) {
+                       err = fd;
+                       goto out2;
+               }
+               submit->sync_fd = fd;
+       }
+
+       submit->fence = lima_sched_context_queue_task(
+               submit->ctx->context + submit->pipe, submit->task,
+               &submit->done);
+
+       ttm_eu_fence_buffer_objects(&submit->ticket, &submit->validated,
+                                   &submit->task->base.s_fence->finished);
+
+out2:
+       if (err)
+               lima_sched_task_fini(submit->task);
+out1:
+        if (err)
+               ttm_eu_backoff_reservation(&submit->ticket, &submit->validated);
+out0:
+       for (i = 0; i < submit->nr_bos; i++) {
+               struct ttm_validate_buffer *vb = submit->vbs + i;
+               if (!vb->bo)
+                       break;
+               drm_gem_object_put_unlocked(&ttm_to_lima_bo(vb->bo)->gem);
+       }
+       return err;
+}
+
+int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, u64 timeout_ns)
+{
+       bool write = op & LIMA_GEM_WAIT_WRITE;
+       struct drm_gem_object *obj;
+       struct lima_bo *bo;
+       signed long ret;
+       unsigned long timeout;
+
+       obj = drm_gem_object_lookup(file, handle);
+       if (!obj)
+               return -ENOENT;
+
+       bo = to_lima_bo(obj);
+
+       timeout = timeout_ns ? lima_timeout_to_jiffies(timeout_ns) : 0;
+
+       ret = lima_bo_reserve(bo, true);
+       if (ret)
+               goto out;
+
+       /* must use long for result check because in 64bit arch int
+        * will overflow if timeout is too large and get <0 result
+        */
+       ret = reservation_object_wait_timeout_rcu(bo->tbo.resv, write, true, 
timeout);
+       if (ret == 0)
+               ret = timeout ? -ETIMEDOUT : -EBUSY;
+       else if (ret > 0)
+               ret = 0;
+
+       lima_bo_unreserve(bo);
+out:
+       drm_gem_object_put_unlocked(obj);
+       return ret;
+}
diff --git a/drivers/gpu/drm/lima/lima_gem.h b/drivers/gpu/drm/lima/lima_gem.h
new file mode 100644
index 000000000000..8e3c4110825d
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_gem.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIMA_GEM_H__
+#define __LIMA_GEM_H__
+
+struct lima_bo;
+struct lima_submit;
+
+struct lima_bo *lima_gem_create_bo(struct drm_device *dev, u32 size, u32 
flags);
+int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
+                          u32 size, u32 flags, u32 *handle);
+void lima_gem_free_object(struct drm_gem_object *obj);
+int lima_gem_object_open(struct drm_gem_object *obj, struct drm_file *file);
+void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *file);
+int lima_gem_mmap_offset(struct drm_file *file, u32 handle, u64 *offset);
+int lima_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+int lima_gem_va_map(struct drm_file *file, u32 handle, u32 flags, u32 va);
+int lima_gem_va_unmap(struct drm_file *file, u32 handle, u32 va);
+int lima_gem_submit(struct drm_file *file, struct lima_submit *submit);
+int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, u64 timeout_ns);
+
+#endif
-- 
2.17.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to