mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-23 07:11:26 +00:00
530 lines
14 KiB
Diff
530 lines
14 KiB
Diff
From fda6ccdbd4930361a5a1dce1d2adf0998f63441e Mon Sep 17 00:00:00 2001
|
|
From: Lima Project Developers <dri-devel@lists.freedesktop.org>
|
|
Date: Wed, 16 May 2018 10:34:29 +0800
|
|
Subject: [PATCH 056/146] drm/lima: add GEM related functions
|
|
|
|
Signed-off-by: Qiang Yu <yuq825@gmail.com>
|
|
Signed-off-by: Erico Nunes <nunes.erico@gmail.com>
|
|
Signed-off-by: Heiko Stuebner <heiko@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.1
|
|
|