From a6b5392c2461a0528b074e490ce964e1e2847e23 Mon Sep 17 00:00:00 2001 From: Kevin Wang 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 Signed-off-by: Kalyan Alle --- 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "amdgpu_sem.h" +#include "amdgpu.h" +#include +#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(¢ity->sem_lock); + list_add(&dep->list, ¢ity->sem_dep_list); + mutex_unlock(¢ity->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(¢ity->sem_dep_list)) + return 0; + + mutex_lock(¢ity->sem_lock); + list_for_each_entry_safe(dep, tmp, ¢ity->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(¢ity->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 + * + */ + + +#ifndef _LINUX_AMDGPU_SEM_H +#define _LINUX_AMDGPU_SEM_H + +#include +#include +#include +#include +#include + +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