aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0153-drm-amdgpu-hybird-add-semaphore-object-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0153-drm-amdgpu-hybird-add-semaphore-object-support.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0153-drm-amdgpu-hybird-add-semaphore-object-support.patch803
1 files changed, 803 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0153-drm-amdgpu-hybird-add-semaphore-object-support.patch b/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0153-drm-amdgpu-hybird-add-semaphore-object-support.patch
new file mode 100644
index 00000000..aff14a58
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/0153-drm-amdgpu-hybird-add-semaphore-object-support.patch
@@ -0,0 +1,803 @@
+From a6b5392c2461a0528b074e490ce964e1e2847e23 Mon Sep 17 00:00:00 2001
+From: Kevin Wang <Kevin1.Wang@amd.com>
+Date: Thu, 30 Aug 2018 12:14:28 +0800
+Subject: [PATCH 0153/2940] drm/amdgpu: [hybird] add semaphore object support
+
+Change-Id: I3acc0a92c9983189fe095272a775c2ebf2b36eac
+Signed-off-by: Kevin Wang <Kevin1.Wang@amd.com>
+Signed-off-by: Kalyan Alle <kalyan.alle@amd.com>
+---
+ drivers/gpu/drm/amd/amdgpu/Makefile | 3 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 3 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 2 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h | 2 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_display.h | 6 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 8 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 8 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_sem.c | 462 ++++++++++++++++++++
+ drivers/gpu/drm/amd/amdgpu/amdgpu_sem.h | 55 +++
+ include/uapi/drm/amdgpu_drm.h | 35 ++
+ 11 files changed, 586 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_sem.c
+ create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_sem.h
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile
+index 860cb8731c7c..cf5c7ed1ac37 100644
+--- a/drivers/gpu/drm/amd/amdgpu/Makefile
++++ b/drivers/gpu/drm/amd/amdgpu/Makefile
+@@ -51,7 +51,8 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
+ amdgpu_prime.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \
+ amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
+ amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o amdgpu_atomfirmware.o \
+- amdgpu_vf_error.o amdgpu_sched.o amdgpu_debugfs.o amdgpu_ids.o
++ amdgpu_vf_error.o amdgpu_sched.o amdgpu_debugfs.o amdgpu_ids.o \
++ amdgpu_sem.o
+
+ # add asic specific block
+ amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+index debab710f5be..f5fcee141fbb 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+@@ -64,6 +64,7 @@
+ #include "amdgpu_sync.h"
+ #include "amdgpu_ring.h"
+ #include "amdgpu_vm.h"
++#include "amdgpu_sem.h"
+ #include "amdgpu_dpm.h"
+ #include "amdgpu_acp.h"
+ #include "amdgpu_uvd.h"
+@@ -482,7 +483,6 @@ struct amdgpu_ib {
+ };
+
+ extern const struct drm_sched_backend_ops amdgpu_sched_ops;
+-
+ /*
+ * file private structure
+ */
+@@ -494,6 +494,8 @@ struct amdgpu_fpriv {
+ struct mutex bo_list_lock;
+ struct idr bo_list_handles;
+ struct amdgpu_ctx_mgr ctx_mgr;
++ spinlock_t sem_handles_lock;
++ struct idr sem_handles;
+ };
+
+ int amdgpu_ib_get(struct amdgpu_device *adev, struct amdgpu_vm *vm,
+@@ -665,6 +667,7 @@ int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
+ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+
++
+ int amdgpu_display_freesync_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+index 363d2cfcd7e9..9af07d366107 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+@@ -33,6 +33,7 @@
+ #include "amdgpu_trace.h"
+ #include "amdgpu_gmc.h"
+ #include "amdgpu_gem.h"
++#include "amdgpu_display.h"
+
+ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
+ struct drm_amdgpu_cs_chunk_fence *data,
+@@ -1189,7 +1190,7 @@ static int amdgpu_cs_dependencies(struct amdgpu_device *adev,
+ }
+ }
+
+- return 0;
++ return amdgpu_sem_add_cs(p->ctx, p->entity, &p->job->sync);
+ }
+
+ static void amdgpu_cs_post_dependencies(struct amdgpu_cs_parser *p)
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+index 987b7f256463..2d7e9fa6e82f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+@@ -104,6 +104,8 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev,
+
+ entity->sequence = 1;
+ entity->fences = &ctx->fences[amdgpu_sched_jobs * i];
++ INIT_LIST_HEAD(&entity->sem_dep_list);
++ mutex_init(&entity->sem_lock);
+ }
+ for (i = 1; i < AMDGPU_HW_IP_NUM; ++i)
+ ctx->entities[i] = ctx->entities[i - 1] +
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h
+index d67c1d285a4f..f7486ea38286 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h
+@@ -33,6 +33,8 @@ struct amdgpu_ctx_entity {
+ uint64_t sequence;
+ struct dma_fence **fences;
+ struct drm_sched_entity entity;
++ struct list_head sem_dep_list;
++ struct mutex sem_lock;
+ };
+
+ struct amdgpu_ctx {
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h
+index 06b922fe0d42..ba7b9fb53864 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h
+@@ -43,5 +43,11 @@ struct drm_framebuffer *
+ amdgpu_display_user_framebuffer_create(struct drm_device *dev,
+ struct drm_file *file_priv,
+ const struct drm_mode_fb_cmd2 *mode_cmd);
++int amdgpu_sem_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *filp);
+
++int amdgpu_sem_add_cs(struct amdgpu_ctx *ctx, struct drm_sched_entity *entity,
++ struct amdgpu_sync *sync);
++
++void amdgpu_sem_destroy(struct amdgpu_fpriv *fpriv, u32 handle);
+ #endif
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
+index 47817e00f54f..29ce4264c1ea 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
+@@ -133,6 +133,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
+ unsigned i;
+ int r = 0;
+ bool need_pipe_sync = false;
++ unsigned extra_nop = 0;
+
+ if (num_ibs == 0)
+ return -EINVAL;
+@@ -159,6 +160,11 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
+ alloc_size = ring->funcs->emit_frame_size + num_ibs *
+ ring->funcs->emit_ib_size;
+
++ if (job && !job->vm_needs_flush && ring->funcs->type == AMDGPU_RING_TYPE_GFX) {
++ extra_nop = 128;
++ alloc_size += extra_nop;
++ }
++
+ r = amdgpu_ring_alloc(ring, alloc_size);
+ if (r) {
+ dev_err(adev->dev, "scheduling IB failed (%d).\n", r);
+@@ -182,6 +188,8 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
+ ring->funcs->insert_start(ring);
+
+ if (job) {
++ amdgpu_ring_insert_nop(ring, extra_nop); /* prevent CE go too fast than DE */
++
+ r = amdgpu_vm_flush(ring, job, need_pipe_sync);
+ if (r) {
+ amdgpu_ring_undo(ring);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+index 0b4e66c4c362..4b97d47252a2 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+@@ -957,6 +957,8 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
+
+ mutex_init(&fpriv->bo_list_lock);
+ idr_init(&fpriv->bo_list_handles);
++ spin_lock_init(&fpriv->sem_handles_lock);
++ idr_init(&fpriv->sem_handles);
+
+ amdgpu_ctx_mgr_init(&fpriv->ctx_mgr);
+
+@@ -993,6 +995,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
+ struct amdgpu_bo_list *list;
++ struct amdgpu_sem *sem;
+ struct amdgpu_bo *pd;
+ unsigned int pasid;
+ int handle;
+@@ -1033,6 +1036,10 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
+ idr_destroy(&fpriv->bo_list_handles);
+ mutex_destroy(&fpriv->bo_list_lock);
+
++ idr_for_each_entry(&fpriv->sem_handles, sem, handle)
++ amdgpu_sem_destroy(fpriv, handle);
++ idr_destroy(&fpriv->sem_handles);
++
+ kfree(fpriv);
+ file_priv->driver_priv = NULL;
+
+@@ -1163,6 +1170,7 @@ const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {
+ DRM_IOCTL_DEF_DRV(AMDGPU_GEM_USERPTR, amdgpu_gem_userptr_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_FREESYNC, amdgpu_display_freesync_ioctl, DRM_MASTER),
+ DRM_IOCTL_DEF_DRV(AMDGPU_GEM_DGMA, amdgpu_gem_dgma_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
++ DRM_IOCTL_DEF_DRV(AMDGPU_SEM, amdgpu_sem_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ };
+ const int amdgpu_max_kms_ioctl = ARRAY_SIZE(amdgpu_ioctls_kms);
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sem.c
+new file mode 100644
+index 000000000000..3d5beb00b0db
+--- /dev/null
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sem.c
+@@ -0,0 +1,462 @@
++/*
++ * Copyright 2016 Advanced Micro Devices, Inc.
++ *
++ * 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.
++ *
++ * Authors:
++ * Chunming Zhou <david1.zhou@amd.com>
++ */
++#include <linux/file.h>
++#include <linux/fs.h>
++#include <linux/kernel.h>
++#include <linux/poll.h>
++#include <linux/seq_file.h>
++#include <linux/export.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/anon_inodes.h>
++#include "amdgpu_sem.h"
++#include "amdgpu.h"
++#include <drm/drmP.h>
++#include "amdgpu_display.h"
++
++#define to_amdgpu_ctx_entity(e) \
++ container_of((e), struct amdgpu_ctx_entity, entity)
++
++static int amdgpu_sem_entity_add(struct amdgpu_fpriv *fpriv,
++ struct drm_amdgpu_sem_in *in,
++ struct amdgpu_sem *sem);
++
++static void amdgpu_sem_core_free(struct kref *kref)
++{
++ struct amdgpu_sem_core *core = container_of(
++ kref, struct amdgpu_sem_core, kref);
++
++ dma_fence_put(core->fence);
++ mutex_destroy(&core->lock);
++ kfree(core);
++}
++
++static void amdgpu_sem_free(struct kref *kref)
++{
++ struct amdgpu_sem *sem = container_of(
++ kref, struct amdgpu_sem, kref);
++
++ kref_put(&sem->base->kref, amdgpu_sem_core_free);
++ kfree(sem);
++}
++
++static inline void amdgpu_sem_get(struct amdgpu_sem *sem)
++{
++ if (sem)
++ kref_get(&sem->kref);
++}
++
++void amdgpu_sem_put(struct amdgpu_sem *sem)
++{
++ if (sem)
++ kref_put(&sem->kref, amdgpu_sem_free);
++}
++
++static int amdgpu_sem_release(struct inode *inode, struct file *file)
++{
++ struct amdgpu_sem_core *core = file->private_data;
++
++ /* set the core->file to null if file got released */
++ mutex_lock(&core->lock);
++ core->file = NULL;
++ mutex_unlock(&core->lock);
++
++ kref_put(&core->kref, amdgpu_sem_core_free);
++ return 0;
++}
++
++static unsigned int amdgpu_sem_poll(struct file *file, poll_table *wait)
++{
++ return 0;
++}
++
++static long amdgpu_sem_file_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ return 0;
++}
++
++static const struct file_operations amdgpu_sem_fops = {
++ .release = amdgpu_sem_release,
++ .poll = amdgpu_sem_poll,
++ .unlocked_ioctl = amdgpu_sem_file_ioctl,
++ .compat_ioctl = amdgpu_sem_file_ioctl,
++};
++
++
++static inline struct amdgpu_sem *amdgpu_sem_lookup(struct amdgpu_fpriv *fpriv, u32 handle)
++{
++ struct amdgpu_sem *sem;
++
++ spin_lock(&fpriv->sem_handles_lock);
++
++ /* Check if we currently have a reference on the object */
++ sem = idr_find(&fpriv->sem_handles, handle);
++ amdgpu_sem_get(sem);
++
++ spin_unlock(&fpriv->sem_handles_lock);
++
++ return sem;
++}
++
++static struct amdgpu_sem_core *amdgpu_sem_core_alloc(void)
++{
++ struct amdgpu_sem_core *core;
++
++ core = kzalloc(sizeof(*core), GFP_KERNEL);
++ if (!core)
++ return NULL;
++
++ kref_init(&core->kref);
++ mutex_init(&core->lock);
++ return core;
++}
++
++static struct amdgpu_sem *amdgpu_sem_alloc(void)
++{
++ struct amdgpu_sem *sem;
++
++ sem = kzalloc(sizeof(*sem), GFP_KERNEL);
++ if (!sem)
++ return NULL;
++
++ kref_init(&sem->kref);
++ INIT_LIST_HEAD(&sem->list);
++
++ return sem;
++}
++
++static int amdgpu_sem_create(struct amdgpu_fpriv *fpriv, u32 *handle)
++{
++ struct amdgpu_sem *sem;
++ struct amdgpu_sem_core *core;
++ int ret;
++
++ sem = amdgpu_sem_alloc();
++ core = amdgpu_sem_core_alloc();
++ if (!sem || !core) {
++ kfree(sem);
++ kfree(core);
++ return -ENOMEM;
++ }
++
++ sem->base = core;
++
++ idr_preload(GFP_KERNEL);
++ spin_lock(&fpriv->sem_handles_lock);
++
++ ret = idr_alloc(&fpriv->sem_handles, sem, 1, 0, GFP_NOWAIT);
++
++ spin_unlock(&fpriv->sem_handles_lock);
++ idr_preload_end();
++
++ if (ret < 0)
++ return ret;
++
++ *handle = ret;
++ return 0;
++}
++
++static int amdgpu_sem_signal(struct amdgpu_fpriv *fpriv,
++ u32 handle, struct dma_fence *fence)
++{
++ struct amdgpu_sem *sem;
++ struct amdgpu_sem_core *core;
++
++ sem = amdgpu_sem_lookup(fpriv, handle);
++ if (!sem)
++ return -EINVAL;
++
++ core = sem->base;
++ mutex_lock(&core->lock);
++ dma_fence_put(core->fence);
++ core->fence = dma_fence_get(fence);
++ mutex_unlock(&core->lock);
++
++ amdgpu_sem_put(sem);
++ return 0;
++}
++
++static int amdgpu_sem_wait(struct amdgpu_fpriv *fpriv,
++ struct drm_amdgpu_sem_in *in)
++{
++ struct amdgpu_sem *sem;
++ int ret;
++
++ sem = amdgpu_sem_lookup(fpriv, in->handle);
++ if (!sem)
++ return -EINVAL;
++
++ ret = amdgpu_sem_entity_add(fpriv, in, sem);
++ amdgpu_sem_put(sem);
++
++ return ret;
++}
++
++static int amdgpu_sem_import(struct amdgpu_fpriv *fpriv,
++ int fd, u32 *handle)
++{
++ struct file *file = fget(fd);
++ struct amdgpu_sem *sem;
++ struct amdgpu_sem_core *core;
++ int ret;
++
++ if (!file)
++ return -EINVAL;
++
++ core = file->private_data;
++ if (!core) {
++ fput(file);
++ return -EINVAL;
++ }
++
++ kref_get(&core->kref);
++ sem = amdgpu_sem_alloc();
++ if (!sem) {
++ ret = -ENOMEM;
++ goto err_sem;
++ }
++
++ sem->base = core;
++
++ idr_preload(GFP_KERNEL);
++ spin_lock(&fpriv->sem_handles_lock);
++
++ ret = idr_alloc(&fpriv->sem_handles, sem, 1, 0, GFP_NOWAIT);
++
++ spin_unlock(&fpriv->sem_handles_lock);
++ idr_preload_end();
++
++ if (ret < 0)
++ goto err_out;
++
++ *handle = ret;
++ fput(file);
++ return 0;
++err_sem:
++ kref_put(&core->kref, amdgpu_sem_core_free);
++err_out:
++ amdgpu_sem_put(sem);
++ fput(file);
++ return ret;
++
++}
++
++static int amdgpu_sem_export(struct amdgpu_fpriv *fpriv,
++ u32 handle, int *fd)
++{
++ struct amdgpu_sem *sem;
++ struct amdgpu_sem_core *core;
++ int ret;
++
++ sem = amdgpu_sem_lookup(fpriv, handle);
++ if (!sem)
++ return -EINVAL;
++
++ core = sem->base;
++ kref_get(&core->kref);
++ mutex_lock(&core->lock);
++ if (!core->file) {
++ core->file = anon_inode_getfile("sem_file",
++ &amdgpu_sem_fops,
++ core, 0);
++ if (IS_ERR(core->file)) {
++ mutex_unlock(&core->lock);
++ ret = -ENOMEM;
++ goto err_put_sem;
++ }
++ } else {
++ get_file(core->file);
++ }
++ mutex_unlock(&core->lock);
++
++ ret = get_unused_fd_flags(O_CLOEXEC);
++ if (ret < 0)
++ goto err_put_file;
++
++ fd_install(ret, core->file);
++
++ *fd = ret;
++ amdgpu_sem_put(sem);
++
++ return 0;
++
++err_put_file:
++ fput(core->file);
++err_put_sem:
++ kref_put(&core->kref, amdgpu_sem_core_free);
++ amdgpu_sem_put(sem);
++ return ret;
++}
++
++void amdgpu_sem_destroy(struct amdgpu_fpriv *fpriv, u32 handle)
++{
++ struct amdgpu_sem *sem = amdgpu_sem_lookup(fpriv, handle);
++ if (!sem)
++ return;
++
++ spin_lock(&fpriv->sem_handles_lock);
++ idr_remove(&fpriv->sem_handles, handle);
++ spin_unlock(&fpriv->sem_handles_lock);
++
++ kref_put(&sem->kref, amdgpu_sem_free);
++ kref_put(&sem->kref, amdgpu_sem_free);
++}
++
++static struct dma_fence *amdgpu_sem_get_fence(struct amdgpu_fpriv *fpriv,
++ struct drm_amdgpu_sem_in *in)
++{
++ struct drm_sched_entity *entity;
++ struct amdgpu_ctx *ctx;
++ struct dma_fence *fence;
++ uint32_t ctx_id, ip_type, ip_instance, ring;
++ int r;
++
++ ctx_id = in->ctx_id;
++ ip_type = in->ip_type;
++ ip_instance = in->ip_instance;
++ ring = in->ring;
++ ctx = amdgpu_ctx_get(fpriv, ctx_id);
++ if (!ctx)
++ return NULL;
++ r = amdgpu_ctx_get_entity(ctx, ip_type,
++ ip_instance, ring, &entity);
++ if (r) {
++ amdgpu_ctx_put(ctx);
++ return NULL;
++ }
++ /* get the last fence of this entity */
++ fence = amdgpu_ctx_get_fence(ctx, entity, in->seq);
++ amdgpu_ctx_put(ctx);
++
++ return fence;
++}
++
++static int amdgpu_sem_entity_add(struct amdgpu_fpriv *fpriv,
++ struct drm_amdgpu_sem_in *in,
++ struct amdgpu_sem *sem)
++{
++ struct amdgpu_ctx *ctx;
++ struct amdgpu_sem_dep *dep;
++ struct drm_sched_entity *entity;
++ struct amdgpu_ctx_entity *centity;
++ uint32_t ctx_id, ip_type, ip_instance, ring;
++ int r;
++
++ ctx_id = in->ctx_id;
++ ip_type = in->ip_type;
++ ip_instance = in->ip_instance;
++ ring = in->ring;
++ ctx = amdgpu_ctx_get(fpriv, ctx_id);
++ if (!ctx)
++ return -EINVAL;
++ r = amdgpu_ctx_get_entity(ctx, ip_type,
++ ip_instance, ring, &entity);
++ if (r)
++ goto err;
++
++ dep = kzalloc(sizeof(*dep), GFP_KERNEL);
++ if (!dep)
++ goto err;
++
++ INIT_LIST_HEAD(&dep->list);
++ dep->fence = dma_fence_get(sem->base->fence);
++
++ centity = to_amdgpu_ctx_entity(entity);
++ mutex_lock(&centity->sem_lock);
++ list_add(&dep->list, &centity->sem_dep_list);
++ mutex_unlock(&centity->sem_lock);
++
++err:
++ amdgpu_ctx_put(ctx);
++ return r;
++}
++
++int amdgpu_sem_add_cs(struct amdgpu_ctx *ctx, struct drm_sched_entity *entity,
++ struct amdgpu_sync *sync)
++{
++ struct amdgpu_sem_dep *dep, *tmp;
++ struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity);
++ int r = 0;
++
++ if (list_empty(&centity->sem_dep_list))
++ return 0;
++
++ mutex_lock(&centity->sem_lock);
++ list_for_each_entry_safe(dep, tmp, &centity->sem_dep_list,
++ list) {
++ r = amdgpu_sync_fence(ctx->adev, sync, dep->fence, true);
++ if (r)
++ goto err;
++ dma_fence_put(dep->fence);
++ list_del_init(&dep->list);
++ kfree(dep);
++ }
++err:
++ mutex_unlock(&centity->sem_lock);
++ return r;
++}
++
++int amdgpu_sem_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *filp)
++{
++ union drm_amdgpu_sem *args = data;
++ struct amdgpu_fpriv *fpriv = filp->driver_priv;
++ struct dma_fence *fence;
++ int r = 0;
++
++ switch (args->in.op) {
++ case AMDGPU_SEM_OP_CREATE_SEM:
++ r = amdgpu_sem_create(fpriv, &args->out.handle);
++ break;
++ case AMDGPU_SEM_OP_WAIT_SEM:
++ r = amdgpu_sem_wait(fpriv, &args->in);
++ break;
++ case AMDGPU_SEM_OP_SIGNAL_SEM:
++ fence = amdgpu_sem_get_fence(fpriv, &args->in);
++ if (IS_ERR(fence)) {
++ r = PTR_ERR(fence);
++ return r;
++ }
++ r = amdgpu_sem_signal(fpriv, args->in.handle, fence);
++ dma_fence_put(fence);
++ break;
++ case AMDGPU_SEM_OP_IMPORT_SEM:
++ r = amdgpu_sem_import(fpriv, args->in.handle, &args->out.handle);
++ break;
++ case AMDGPU_SEM_OP_EXPORT_SEM:
++ r = amdgpu_sem_export(fpriv, args->in.handle, &args->out.fd);
++ break;
++ case AMDGPU_SEM_OP_DESTROY_SEM:
++ amdgpu_sem_destroy(fpriv, args->in.handle);
++ break;
++ default:
++ r = -EINVAL;
++ break;
++ }
++
++ return r;
++}
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sem.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sem.h
+new file mode 100644
+index 000000000000..08cda204f177
+--- /dev/null
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sem.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright 2016 Advanced Micro Devices, Inc.
++ *
++ * 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.
++ *
++ * Authors: Chunming Zhou <david1.zhou@amd.com>
++ *
++ */
++
++
++#ifndef _LINUX_AMDGPU_SEM_H
++#define _LINUX_AMDGPU_SEM_H
++
++#include <linux/types.h>
++#include <linux/kref.h>
++#include <linux/ktime.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++
++struct amdgpu_sem_core {
++ struct file *file;
++ struct kref kref;
++ struct dma_fence *fence;
++ struct mutex lock;
++};
++
++struct amdgpu_sem_dep {
++ struct dma_fence *fence;
++ struct list_head list;
++};
++
++struct amdgpu_sem {
++ struct amdgpu_sem_core *base;
++ struct kref kref;
++ struct list_head list;
++};
++
++void amdgpu_sem_put(struct amdgpu_sem *sem);
++#endif /* _LINUX_AMDGPU_SEM_H */
+diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h
+index 72822f593f57..34ebb2b7f72d 100644
+--- a/include/uapi/drm/amdgpu_drm.h
++++ b/include/uapi/drm/amdgpu_drm.h
+@@ -58,6 +58,9 @@ extern "C" {
+ #define DRM_AMDGPU_FREESYNC 0x5d
+ #define DRM_AMDGPU_GEM_DGMA 0x5c
+
++/* hybrid specific ioctls */
++#define DRM_AMDGPU_SEM 0x5b
++
+ #define DRM_IOCTL_AMDGPU_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_CREATE, union drm_amdgpu_gem_create)
+ #define DRM_IOCTL_AMDGPU_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_MMAP, union drm_amdgpu_gem_mmap)
+ #define DRM_IOCTL_AMDGPU_CTX DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_CTX, union drm_amdgpu_ctx)
+@@ -101,6 +104,9 @@ extern "C" {
+ * %AMDGPU_GEM_DOMAIN_OA Ordered append, used by 3D or Compute engines
+ * for appending data.
+ */
++/* hybrid specific ioctls */
++#define DRM_IOCTL_AMDGPU_SEM DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_SEM, union drm_amdgpu_sem)
++
+ #define AMDGPU_GEM_DOMAIN_CPU 0x1
+ #define AMDGPU_GEM_DOMAIN_GTT 0x2
+ #define AMDGPU_GEM_DOMAIN_VRAM 0x4
+@@ -264,6 +270,35 @@ union drm_amdgpu_ctx {
+ union drm_amdgpu_ctx_out out;
+ };
+
++/* sem related */
++#define AMDGPU_SEM_OP_CREATE_SEM 1
++#define AMDGPU_SEM_OP_WAIT_SEM 2
++#define AMDGPU_SEM_OP_SIGNAL_SEM 3
++#define AMDGPU_SEM_OP_DESTROY_SEM 4
++#define AMDGPU_SEM_OP_IMPORT_SEM 5
++#define AMDGPU_SEM_OP_EXPORT_SEM 6
++
++struct drm_amdgpu_sem_in {
++ /** AMDGPU_SEM_OP_* */
++ uint32_t op;
++ uint32_t handle;
++ uint32_t ctx_id;
++ uint32_t ip_type;
++ uint32_t ip_instance;
++ uint32_t ring;
++ uint64_t seq;
++};
++
++union drm_amdgpu_sem_out {
++ int32_t fd;
++ uint32_t handle;
++};
++
++union drm_amdgpu_sem {
++ struct drm_amdgpu_sem_in in;
++ union drm_amdgpu_sem_out out;
++};
++
+ /* vm ioctl */
+ #define AMDGPU_VM_OP_RESERVE_VMID 1
+ #define AMDGPU_VM_OP_UNRESERVE_VMID 2
+--
+2.17.1
+