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