/* 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 = kzalloc_objs(*syncobjs, nr_in_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;} voidmsm_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 = kzalloc_objs(*post_deps, nr_syncobjs, 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;} voidmsm_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); } }}
/* 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 = kzalloc_objs(*syncobjs, nr_in_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 = kzalloc_objs(*post_deps, nr_syncobjs,
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);
}
}
}