172 lines · 4.0 KB · C
RawDownload
/* 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);		}	}}