xref: /linux/drivers/gpu/drm/msm/msm_submitqueue.c (revision 632ad5510114eb3866bc519bd216860d48ccf77c)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2017 The Linux Foundation. All rights reserved.
3  */
4 
5 #include <linux/kref.h>
6 #include <linux/uaccess.h>
7 
8 #include "msm_gpu.h"
9 
10 int msm_context_set_sysprof(struct msm_context *ctx, struct msm_gpu *gpu, int sysprof)
11 {
12 	/*
13 	 * Since pm_runtime and sysprof_active are both refcounts, we
14 	 * call apply the new value first, and then unwind the previous
15 	 * value
16 	 */
17 
18 	switch (sysprof) {
19 	default:
20 		return UERR(EINVAL, gpu->dev, "Invalid sysprof: %d", sysprof);
21 	case 2:
22 		pm_runtime_get_sync(&gpu->pdev->dev);
23 		fallthrough;
24 	case 1:
25 		refcount_inc(&gpu->sysprof_active);
26 		fallthrough;
27 	case 0:
28 		break;
29 	}
30 
31 	/* unwind old value: */
32 	switch (ctx->sysprof) {
33 	case 2:
34 		pm_runtime_put_autosuspend(&gpu->pdev->dev);
35 		fallthrough;
36 	case 1:
37 		refcount_dec(&gpu->sysprof_active);
38 		fallthrough;
39 	case 0:
40 		break;
41 	}
42 
43 	/* Some gpu families require additional setup for sysprof */
44 	if (gpu->funcs->sysprof_setup)
45 		gpu->funcs->sysprof_setup(gpu, false);
46 
47 	ctx->sysprof = sysprof;
48 
49 	return 0;
50 }
51 
52 void __msm_context_destroy(struct kref *kref)
53 {
54 	struct msm_context *ctx = container_of(kref,
55 		struct msm_context, ref);
56 	int i;
57 
58 	for (i = 0; i < ARRAY_SIZE(ctx->entities); i++) {
59 		if (!ctx->entities[i])
60 			continue;
61 
62 		drm_sched_entity_destroy(ctx->entities[i]);
63 		kfree(ctx->entities[i]);
64 	}
65 
66 	drm_gpuvm_put(ctx->vm);
67 	kfree(ctx->comm);
68 	kfree(ctx->cmdline);
69 	kfree(ctx->perfctx);
70 	kfree(ctx);
71 }
72 
73 void msm_submitqueue_destroy(struct kref *kref)
74 {
75 	struct msm_gpu_submitqueue *queue = container_of(kref,
76 		struct msm_gpu_submitqueue, ref);
77 
78 	idr_destroy(&queue->fence_idr);
79 
80 	if (queue->entity == &queue->_vm_bind_entity[0])
81 		drm_sched_entity_destroy(queue->entity);
82 
83 	msm_context_put(queue->ctx);
84 
85 	kfree(queue);
86 }
87 
88 struct msm_gpu_submitqueue *msm_submitqueue_get(struct msm_context *ctx,
89 		u32 id)
90 {
91 	struct msm_gpu_submitqueue *entry;
92 
93 	if (!ctx)
94 		return NULL;
95 
96 	read_lock(&ctx->queuelock);
97 
98 	list_for_each_entry(entry, &ctx->submitqueues, node) {
99 		if (entry->id == id) {
100 			kref_get(&entry->ref);
101 			read_unlock(&ctx->queuelock);
102 
103 			return entry;
104 		}
105 	}
106 
107 	read_unlock(&ctx->queuelock);
108 	return NULL;
109 }
110 
111 void msm_submitqueue_close(struct msm_context *ctx)
112 {
113 	struct msm_gpu_submitqueue *queue, *tmp;
114 
115 	if (!ctx)
116 		return;
117 
118 	/*
119 	 * No lock needed in close and there won't
120 	 * be any more user ioctls coming our way
121 	 */
122 	list_for_each_entry_safe(queue, tmp, &ctx->submitqueues, node) {
123 		if (queue->entity == &queue->_vm_bind_entity[0])
124 			drm_sched_entity_flush(queue->entity, MAX_WAIT_SCHED_ENTITY_Q_EMPTY);
125 		list_del(&queue->node);
126 		msm_submitqueue_put(queue);
127 	}
128 
129 	if (!ctx->vm)
130 		return;
131 
132 	msm_gem_vm_close(ctx->vm);
133 }
134 
135 static struct drm_sched_entity *
136 get_sched_entity(struct msm_context *ctx, struct msm_ringbuffer *ring,
137 		 unsigned ring_nr, enum drm_sched_priority sched_prio)
138 {
139 	static DEFINE_MUTEX(entity_lock);
140 	unsigned idx = (ring_nr * NR_SCHED_PRIORITIES) + sched_prio;
141 
142 	/* We should have already validated that the requested priority is
143 	 * valid by the time we get here.
144 	 */
145 	if (WARN_ON(idx >= ARRAY_SIZE(ctx->entities)))
146 		return ERR_PTR(-EINVAL);
147 
148 	mutex_lock(&entity_lock);
149 
150 	if (!ctx->entities[idx]) {
151 		struct drm_sched_entity *entity;
152 		struct drm_gpu_scheduler *sched = &ring->sched;
153 		int ret;
154 
155 		entity = kzalloc_obj(*ctx->entities[idx]);
156 
157 		ret = drm_sched_entity_init(entity, sched_prio, &sched, 1, NULL);
158 		if (ret) {
159 			mutex_unlock(&entity_lock);
160 			kfree(entity);
161 			return ERR_PTR(ret);
162 		}
163 
164 		ctx->entities[idx] = entity;
165 	}
166 
167 	mutex_unlock(&entity_lock);
168 
169 	return ctx->entities[idx];
170 }
171 
172 int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
173 		u32 prio, u32 flags, u32 *id)
174 {
175 	struct msm_drm_private *priv = drm->dev_private;
176 	struct msm_gpu_submitqueue *queue;
177 	enum drm_sched_priority sched_prio;
178 	unsigned ring_nr;
179 	int ret;
180 
181 	if (!ctx)
182 		return -ENODEV;
183 
184 	if (!priv->gpu)
185 		return -ENODEV;
186 
187 	if (flags & MSM_SUBMITQUEUE_VM_BIND) {
188 		unsigned sz;
189 
190 		/* Not allowed for kernel managed VMs (ie. kernel allocs VA) */
191 		if (!msm_context_is_vmbind(ctx))
192 			return -EINVAL;
193 
194 		if (prio)
195 			return -EINVAL;
196 
197 		sz = struct_size(queue, _vm_bind_entity, 1);
198 		queue = kzalloc(sz, GFP_KERNEL);
199 	} else {
200 		extern int enable_preemption;
201 		bool preemption_supported =
202 			priv->gpu->nr_rings == 1 && enable_preemption != 0;
203 
204 		if (flags & MSM_SUBMITQUEUE_ALLOW_PREEMPT && preemption_supported)
205 			return -EINVAL;
206 
207 		ret = msm_gpu_convert_priority(priv->gpu, prio, &ring_nr, &sched_prio);
208 		if (ret)
209 			return ret;
210 
211 		queue = kzalloc_obj(*queue);
212 	}
213 
214 	if (!queue)
215 		return -ENOMEM;
216 
217 	kref_init(&queue->ref);
218 	queue->flags = flags;
219 
220 	if (flags & MSM_SUBMITQUEUE_VM_BIND) {
221 		struct drm_gpu_scheduler *sched = &to_msm_vm(msm_context_vm(drm, ctx))->sched;
222 
223 		queue->entity = &queue->_vm_bind_entity[0];
224 
225 		drm_sched_entity_init(queue->entity, DRM_SCHED_PRIORITY_KERNEL,
226 				      &sched, 1, NULL);
227 	} else {
228 		queue->ring_nr = ring_nr;
229 
230 		queue->entity = get_sched_entity(ctx, priv->gpu->rb[ring_nr],
231 						 ring_nr, sched_prio);
232 	}
233 
234 	if (IS_ERR(queue->entity)) {
235 		ret = PTR_ERR(queue->entity);
236 		kfree(queue);
237 		return ret;
238 	}
239 
240 	write_lock(&ctx->queuelock);
241 
242 	queue->ctx = msm_context_get(ctx);
243 	queue->id = ctx->queueid++;
244 
245 	if (id)
246 		*id = queue->id;
247 
248 	idr_init(&queue->fence_idr);
249 	spin_lock_init(&queue->idr_lock);
250 	mutex_init(&queue->lock);
251 
252 	list_add_tail(&queue->node, &ctx->submitqueues);
253 
254 	write_unlock(&ctx->queuelock);
255 
256 	return 0;
257 }
258 
259 /*
260  * Create the default submit-queue (id==0), used for backwards compatibility
261  * for userspace that pre-dates the introduction of submitqueues.
262  */
263 int msm_submitqueue_init(struct drm_device *drm, struct msm_context *ctx)
264 {
265 	struct msm_drm_private *priv = drm->dev_private;
266 	int default_prio, max_priority;
267 
268 	if (!priv->gpu)
269 		return -ENODEV;
270 
271 	max_priority = (priv->gpu->nr_rings * NR_SCHED_PRIORITIES) - 1;
272 
273 	/*
274 	 * Pick a medium priority level as default.  Lower numeric value is
275 	 * higher priority, so round-up to pick a priority that is not higher
276 	 * than the middle priority level.
277 	 */
278 	default_prio = DIV_ROUND_UP(max_priority, 2);
279 
280 	return msm_submitqueue_create(drm, ctx, default_prio, 0, NULL);
281 }
282 
283 static int msm_submitqueue_query_faults(struct msm_gpu_submitqueue *queue,
284 		struct drm_msm_submitqueue_query *args)
285 {
286 	size_t size = min_t(size_t, args->len, sizeof(queue->faults));
287 	int ret;
288 
289 	/* If a zero length was passed in, return the data size we expect */
290 	if (!args->len) {
291 		args->len = sizeof(queue->faults);
292 		return 0;
293 	}
294 
295 	/* Set the length to the actual size of the data */
296 	args->len = size;
297 
298 	ret = copy_to_user(u64_to_user_ptr(args->data), &queue->faults, size);
299 
300 	return ret ? -EFAULT : 0;
301 }
302 
303 int msm_submitqueue_query(struct drm_device *drm, struct msm_context *ctx,
304 		struct drm_msm_submitqueue_query *args)
305 {
306 	struct msm_gpu_submitqueue *queue;
307 	int ret = -EINVAL;
308 
309 	if (args->pad)
310 		return -EINVAL;
311 
312 	queue = msm_submitqueue_get(ctx, args->id);
313 	if (!queue)
314 		return -ENOENT;
315 
316 	if (args->param == MSM_SUBMITQUEUE_PARAM_FAULTS)
317 		ret = msm_submitqueue_query_faults(queue, args);
318 
319 	msm_submitqueue_put(queue);
320 
321 	return ret;
322 }
323 
324 int msm_submitqueue_remove(struct msm_context *ctx, u32 id)
325 {
326 	struct msm_gpu_submitqueue *entry;
327 
328 	if (!ctx)
329 		return 0;
330 
331 	/*
332 	 * id 0 is the "default" queue and can't be destroyed
333 	 * by the user
334 	 */
335 	if (!id)
336 		return -ENOENT;
337 
338 	write_lock(&ctx->queuelock);
339 
340 	list_for_each_entry(entry, &ctx->submitqueues, node) {
341 		if (entry->id == id) {
342 			list_del(&entry->node);
343 			write_unlock(&ctx->queuelock);
344 
345 			msm_submitqueue_put(entry);
346 			return 0;
347 		}
348 	}
349 
350 	write_unlock(&ctx->queuelock);
351 	return -ENOENT;
352 }
353 
354