mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-28 18:10:32 +00:00

We'll be re-using these for the VM_BIND ioctl. Also, rename a few things in the uapi header to reflect that syncobj use is not specific to the submit ioctl. Signed-off-by: Rob Clark <robdclark@chromium.org> Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com> Tested-by: Antonino Maniscalco <antomani103@gmail.com> Reviewed-by: Antonino Maniscalco <antomani103@gmail.com> Patchwork: https://patchwork.freedesktop.org/patch/661512/
173 lines
4.0 KiB
C
173 lines
4.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/* Copyright (C) 2020 Google, Inc */
|
|
|
|
#include "drm/drm_drv.h"
|
|
|
|
#include "msm_drv.h"
|
|
#include "msm_syncobj.h"
|
|
|
|
struct drm_syncobj **
|
|
msm_syncobj_parse_deps(struct drm_device *dev,
|
|
struct drm_sched_job *job,
|
|
struct drm_file *file,
|
|
uint64_t in_syncobjs_addr,
|
|
uint32_t nr_in_syncobjs,
|
|
size_t syncobj_stride)
|
|
{
|
|
struct drm_syncobj **syncobjs = NULL;
|
|
struct drm_msm_syncobj syncobj_desc = {0};
|
|
int ret = 0;
|
|
uint32_t i, j;
|
|
|
|
syncobjs = kcalloc(nr_in_syncobjs, sizeof(*syncobjs),
|
|
GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
|
|
if (!syncobjs)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
for (i = 0; i < nr_in_syncobjs; ++i) {
|
|
uint64_t address = in_syncobjs_addr + i * syncobj_stride;
|
|
|
|
if (copy_from_user(&syncobj_desc,
|
|
u64_to_user_ptr(address),
|
|
min(syncobj_stride, sizeof(syncobj_desc)))) {
|
|
ret = -EFAULT;
|
|
break;
|
|
}
|
|
|
|
if (syncobj_desc.point &&
|
|
!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) {
|
|
ret = UERR(EOPNOTSUPP, dev, "syncobj timeline unsupported");
|
|
break;
|
|
}
|
|
|
|
if (syncobj_desc.flags & ~MSM_SYNCOBJ_FLAGS) {
|
|
ret = UERR(EINVAL, dev, "invalid syncobj flags: %x", syncobj_desc.flags);
|
|
break;
|
|
}
|
|
|
|
ret = drm_sched_job_add_syncobj_dependency(job, file,
|
|
syncobj_desc.handle,
|
|
syncobj_desc.point);
|
|
if (ret)
|
|
break;
|
|
|
|
if (syncobj_desc.flags & MSM_SYNCOBJ_RESET) {
|
|
syncobjs[i] = drm_syncobj_find(file, syncobj_desc.handle);
|
|
if (!syncobjs[i]) {
|
|
ret = UERR(EINVAL, dev, "invalid syncobj handle: %u", i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ret) {
|
|
for (j = 0; j <= i; ++j) {
|
|
if (syncobjs[j])
|
|
drm_syncobj_put(syncobjs[j]);
|
|
}
|
|
kfree(syncobjs);
|
|
return ERR_PTR(ret);
|
|
}
|
|
return syncobjs;
|
|
}
|
|
|
|
void
|
|
msm_syncobj_reset(struct drm_syncobj **syncobjs, uint32_t nr_syncobjs)
|
|
{
|
|
uint32_t i;
|
|
|
|
for (i = 0; syncobjs && i < nr_syncobjs; ++i) {
|
|
if (syncobjs[i])
|
|
drm_syncobj_replace_fence(syncobjs[i], NULL);
|
|
}
|
|
}
|
|
|
|
struct msm_syncobj_post_dep *
|
|
msm_syncobj_parse_post_deps(struct drm_device *dev,
|
|
struct drm_file *file,
|
|
uint64_t syncobjs_addr,
|
|
uint32_t nr_syncobjs,
|
|
size_t syncobj_stride)
|
|
{
|
|
struct msm_syncobj_post_dep *post_deps;
|
|
struct drm_msm_syncobj syncobj_desc = {0};
|
|
int ret = 0;
|
|
uint32_t i, j;
|
|
|
|
post_deps = kcalloc(nr_syncobjs, sizeof(*post_deps),
|
|
GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
|
|
if (!post_deps)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
for (i = 0; i < nr_syncobjs; ++i) {
|
|
uint64_t address = syncobjs_addr + i * syncobj_stride;
|
|
|
|
if (copy_from_user(&syncobj_desc,
|
|
u64_to_user_ptr(address),
|
|
min(syncobj_stride, sizeof(syncobj_desc)))) {
|
|
ret = -EFAULT;
|
|
break;
|
|
}
|
|
|
|
post_deps[i].point = syncobj_desc.point;
|
|
|
|
if (syncobj_desc.flags) {
|
|
ret = UERR(EINVAL, dev, "invalid syncobj flags");
|
|
break;
|
|
}
|
|
|
|
if (syncobj_desc.point) {
|
|
if (!drm_core_check_feature(dev,
|
|
DRIVER_SYNCOBJ_TIMELINE)) {
|
|
ret = UERR(EOPNOTSUPP, dev, "syncobj timeline unsupported");
|
|
break;
|
|
}
|
|
|
|
post_deps[i].chain = dma_fence_chain_alloc();
|
|
if (!post_deps[i].chain) {
|
|
ret = -ENOMEM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
post_deps[i].syncobj =
|
|
drm_syncobj_find(file, syncobj_desc.handle);
|
|
if (!post_deps[i].syncobj) {
|
|
ret = UERR(EINVAL, dev, "invalid syncobj handle");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ret) {
|
|
for (j = 0; j <= i; ++j) {
|
|
dma_fence_chain_free(post_deps[j].chain);
|
|
if (post_deps[j].syncobj)
|
|
drm_syncobj_put(post_deps[j].syncobj);
|
|
}
|
|
|
|
kfree(post_deps);
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
return post_deps;
|
|
}
|
|
|
|
void
|
|
msm_syncobj_process_post_deps(struct msm_syncobj_post_dep *post_deps,
|
|
uint32_t count, struct dma_fence *fence)
|
|
{
|
|
uint32_t i;
|
|
|
|
for (i = 0; post_deps && i < count; ++i) {
|
|
if (post_deps[i].chain) {
|
|
drm_syncobj_add_point(post_deps[i].syncobj,
|
|
post_deps[i].chain,
|
|
fence, post_deps[i].point);
|
|
post_deps[i].chain = NULL;
|
|
} else {
|
|
drm_syncobj_replace_fence(post_deps[i].syncobj,
|
|
fence);
|
|
}
|
|
}
|
|
}
|