File Index
Files and directories
Sign in
FILE

msm_syncobj.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/msm/msm_syncobj.c C
  1/* SPDX-License-Identifier: GPL-2.0-only */
  2/* Copyright (C) 2020 Google, Inc */
  3
  4#include "drm/drm_drv.h"
  5
  6#include "msm_drv.h"
  7#include "msm_syncobj.h"
  8
  9struct drm_syncobj **
 10msm_syncobj_parse_deps(struct drm_device *dev,
 11		       struct drm_sched_job *job,
 12		       struct drm_file *file,
 13		       uint64_t in_syncobjs_addr,
 14		       uint32_t nr_in_syncobjs,
 15		       size_t syncobj_stride)
 16{
 17	struct drm_syncobj **syncobjs = NULL;
 18	struct drm_msm_syncobj syncobj_desc = {0};
 19	int ret = 0;
 20	uint32_t i, j;
 21
 22	syncobjs = kcalloc(nr_in_syncobjs, sizeof(*syncobjs),
 23	                   GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
 24	if (!syncobjs)
 25		return ERR_PTR(-ENOMEM);
 26
 27	for (i = 0; i < nr_in_syncobjs; ++i) {
 28		uint64_t address = in_syncobjs_addr + i * syncobj_stride;
 29
 30		if (copy_from_user(&syncobj_desc,
 31			           u64_to_user_ptr(address),
 32			           min(syncobj_stride, sizeof(syncobj_desc)))) {
 33			ret = -EFAULT;
 34			break;
 35		}
 36
 37		if (syncobj_desc.point &&
 38		    !drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) {
 39			ret = UERR(EOPNOTSUPP, dev, "syncobj timeline unsupported");
 40			break;
 41		}
 42
 43		if (syncobj_desc.flags & ~MSM_SYNCOBJ_FLAGS) {
 44			ret = UERR(EINVAL, dev, "invalid syncobj flags: %x", syncobj_desc.flags);
 45			break;
 46		}
 47
 48		ret = drm_sched_job_add_syncobj_dependency(job, file,
 49						   syncobj_desc.handle,
 50						   syncobj_desc.point);
 51		if (ret)
 52			break;
 53
 54		if (syncobj_desc.flags & MSM_SYNCOBJ_RESET) {
 55			syncobjs[i] = drm_syncobj_find(file, syncobj_desc.handle);
 56			if (!syncobjs[i]) {
 57				ret = UERR(EINVAL, dev, "invalid syncobj handle: %u", i);
 58				break;
 59			}
 60		}
 61	}
 62
 63	if (ret) {
 64		for (j = 0; j <= i; ++j) {
 65			if (syncobjs[j])
 66				drm_syncobj_put(syncobjs[j]);
 67		}
 68		kfree(syncobjs);
 69		return ERR_PTR(ret);
 70	}
 71	return syncobjs;
 72}
 73
 74void
 75msm_syncobj_reset(struct drm_syncobj **syncobjs, uint32_t nr_syncobjs)
 76{
 77	uint32_t i;
 78
 79	for (i = 0; syncobjs && i < nr_syncobjs; ++i) {
 80		if (syncobjs[i])
 81			drm_syncobj_replace_fence(syncobjs[i], NULL);
 82	}
 83}
 84
 85struct msm_syncobj_post_dep *
 86msm_syncobj_parse_post_deps(struct drm_device *dev,
 87			    struct drm_file *file,
 88			    uint64_t syncobjs_addr,
 89			    uint32_t nr_syncobjs,
 90			    size_t syncobj_stride)
 91{
 92	struct msm_syncobj_post_dep *post_deps;
 93	struct drm_msm_syncobj syncobj_desc = {0};
 94	int ret = 0;
 95	uint32_t i, j;
 96
 97	post_deps = kcalloc(nr_syncobjs, sizeof(*post_deps),
 98			    GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
 99	if (!post_deps)
100		return ERR_PTR(-ENOMEM);
101
102	for (i = 0; i < nr_syncobjs; ++i) {
103		uint64_t address = syncobjs_addr + i * syncobj_stride;
104
105		if (copy_from_user(&syncobj_desc,
106			           u64_to_user_ptr(address),
107			           min(syncobj_stride, sizeof(syncobj_desc)))) {
108			ret = -EFAULT;
109			break;
110		}
111
112		post_deps[i].point = syncobj_desc.point;
113
114		if (syncobj_desc.flags) {
115			ret = UERR(EINVAL, dev, "invalid syncobj flags");
116			break;
117		}
118
119		if (syncobj_desc.point) {
120			if (!drm_core_check_feature(dev,
121			                            DRIVER_SYNCOBJ_TIMELINE)) {
122				ret = UERR(EOPNOTSUPP, dev, "syncobj timeline unsupported");
123				break;
124			}
125
126			post_deps[i].chain = dma_fence_chain_alloc();
127			if (!post_deps[i].chain) {
128				ret = -ENOMEM;
129				break;
130			}
131		}
132
133		post_deps[i].syncobj =
134			drm_syncobj_find(file, syncobj_desc.handle);
135		if (!post_deps[i].syncobj) {
136			ret = UERR(EINVAL, dev, "invalid syncobj handle");
137			break;
138		}
139	}
140
141	if (ret) {
142		for (j = 0; j <= i; ++j) {
143			dma_fence_chain_free(post_deps[j].chain);
144			if (post_deps[j].syncobj)
145				drm_syncobj_put(post_deps[j].syncobj);
146		}
147
148		kfree(post_deps);
149		return ERR_PTR(ret);
150	}
151
152	return post_deps;
153}
154
155void
156msm_syncobj_process_post_deps(struct msm_syncobj_post_dep *post_deps,
157			      uint32_t count, struct dma_fence *fence)
158{
159	uint32_t i;
160
161	for (i = 0; post_deps && i < count; ++i) {
162		if (post_deps[i].chain) {
163			drm_syncobj_add_point(post_deps[i].syncobj,
164			                      post_deps[i].chain,
165			                      fence, post_deps[i].point);
166			post_deps[i].chain = NULL;
167		} else {
168			drm_syncobj_replace_fence(post_deps[i].syncobj,
169			                          fence);
170		}
171	}
172}
~/ Read-only file preview.