1 // SPDX-License-Identifier: GPL-2.0-only OR MIT
2 /* Copyright (c) 2023 Imagination Technologies Ltd. */
3
4 #include "pvr_context.h"
5 #include "pvr_device.h"
6 #include "pvr_drv.h"
7 #include "pvr_gem.h"
8 #include "pvr_hwrt.h"
9 #include "pvr_job.h"
10 #include "pvr_mmu.h"
11 #include "pvr_power.h"
12 #include "pvr_rogue_fwif.h"
13 #include "pvr_rogue_fwif_client.h"
14 #include "pvr_stream.h"
15 #include "pvr_stream_defs.h"
16 #include "pvr_sync.h"
17
18 #include <drm/drm_exec.h>
19 #include <drm/drm_gem.h>
20 #include <linux/types.h>
21 #include <uapi/drm/pvr_drm.h>
22
pvr_job_release(struct kref * kref)23 static void pvr_job_release(struct kref *kref)
24 {
25 struct pvr_job *job = container_of(kref, struct pvr_job, ref_count);
26
27 xa_erase(&job->pvr_dev->job_ids, job->id);
28
29 pvr_hwrt_data_put(job->hwrt);
30 pvr_context_put(job->ctx);
31
32 WARN_ON(job->paired_job);
33
34 pvr_queue_job_cleanup(job);
35 pvr_job_release_pm_ref(job);
36
37 kfree(job->cmd);
38 kfree(job);
39 }
40
41 /**
42 * pvr_job_put() - Release reference on job
43 * @job: Target job.
44 */
45 void
pvr_job_put(struct pvr_job * job)46 pvr_job_put(struct pvr_job *job)
47 {
48 if (job)
49 kref_put(&job->ref_count, pvr_job_release);
50 }
51
52 /**
53 * pvr_job_process_stream() - Build job FW structure from stream
54 * @pvr_dev: Device pointer.
55 * @cmd_defs: Stream definition.
56 * @stream: Pointer to command stream.
57 * @stream_size: Size of command stream, in bytes.
58 * @job: Pointer to job.
59 *
60 * Caller is responsible for freeing the output structure.
61 *
62 * Returns:
63 * * 0 on success,
64 * * -%ENOMEM on out of memory, or
65 * * -%EINVAL on malformed stream.
66 */
67 static int
pvr_job_process_stream(struct pvr_device * pvr_dev,const struct pvr_stream_cmd_defs * cmd_defs,void * stream,u32 stream_size,struct pvr_job * job)68 pvr_job_process_stream(struct pvr_device *pvr_dev, const struct pvr_stream_cmd_defs *cmd_defs,
69 void *stream, u32 stream_size, struct pvr_job *job)
70 {
71 int err;
72
73 job->cmd = kzalloc(cmd_defs->dest_size, GFP_KERNEL);
74 if (!job->cmd)
75 return -ENOMEM;
76
77 job->cmd_len = cmd_defs->dest_size;
78
79 err = pvr_stream_process(pvr_dev, cmd_defs, stream, stream_size, job->cmd);
80 if (err)
81 kfree(job->cmd);
82
83 return err;
84 }
85
pvr_fw_cmd_init(struct pvr_device * pvr_dev,struct pvr_job * job,const struct pvr_stream_cmd_defs * stream_def,u64 stream_userptr,u32 stream_len)86 static int pvr_fw_cmd_init(struct pvr_device *pvr_dev, struct pvr_job *job,
87 const struct pvr_stream_cmd_defs *stream_def,
88 u64 stream_userptr, u32 stream_len)
89 {
90 void *stream;
91 int err;
92
93 stream = memdup_user(u64_to_user_ptr(stream_userptr), stream_len);
94 if (IS_ERR(stream))
95 return PTR_ERR(stream);
96
97 err = pvr_job_process_stream(pvr_dev, stream_def, stream, stream_len, job);
98
99 kfree(stream);
100 return err;
101 }
102
103 static u32
convert_geom_flags(u32 in_flags)104 convert_geom_flags(u32 in_flags)
105 {
106 u32 out_flags = 0;
107
108 if (in_flags & DRM_PVR_SUBMIT_JOB_GEOM_CMD_FIRST)
109 out_flags |= ROGUE_GEOM_FLAGS_FIRSTKICK;
110 if (in_flags & DRM_PVR_SUBMIT_JOB_GEOM_CMD_LAST)
111 out_flags |= ROGUE_GEOM_FLAGS_LASTKICK;
112 if (in_flags & DRM_PVR_SUBMIT_JOB_GEOM_CMD_SINGLE_CORE)
113 out_flags |= ROGUE_GEOM_FLAGS_SINGLE_CORE;
114
115 return out_flags;
116 }
117
118 static u32
convert_frag_flags(u32 in_flags)119 convert_frag_flags(u32 in_flags)
120 {
121 u32 out_flags = 0;
122
123 if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_SINGLE_CORE)
124 out_flags |= ROGUE_FRAG_FLAGS_SINGLE_CORE;
125 if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_DEPTHBUFFER)
126 out_flags |= ROGUE_FRAG_FLAGS_DEPTHBUFFER;
127 if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_STENCILBUFFER)
128 out_flags |= ROGUE_FRAG_FLAGS_STENCILBUFFER;
129 if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_PREVENT_CDM_OVERLAP)
130 out_flags |= ROGUE_FRAG_FLAGS_PREVENT_CDM_OVERLAP;
131 if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_SCRATCHBUFFER)
132 out_flags |= ROGUE_FRAG_FLAGS_SCRATCHBUFFER;
133 if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_GET_VIS_RESULTS)
134 out_flags |= ROGUE_FRAG_FLAGS_GET_VIS_RESULTS;
135 if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_DISABLE_PIXELMERGE)
136 out_flags |= ROGUE_FRAG_FLAGS_DISABLE_PIXELMERGE;
137
138 return out_flags;
139 }
140
141 static int
pvr_geom_job_fw_cmd_init(struct pvr_job * job,struct drm_pvr_job * args)142 pvr_geom_job_fw_cmd_init(struct pvr_job *job,
143 struct drm_pvr_job *args)
144 {
145 struct rogue_fwif_cmd_geom *cmd;
146 int err;
147
148 if (args->flags & ~DRM_PVR_SUBMIT_JOB_GEOM_CMD_FLAGS_MASK)
149 return -EINVAL;
150
151 if (job->ctx->type != DRM_PVR_CTX_TYPE_RENDER)
152 return -EINVAL;
153
154 if (!job->hwrt)
155 return -EINVAL;
156
157 job->fw_ccb_cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_GEOM;
158 err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_geom_stream,
159 args->cmd_stream, args->cmd_stream_len);
160 if (err)
161 return err;
162
163 cmd = job->cmd;
164 cmd->cmd_shared.cmn.frame_num = 0;
165 cmd->flags = convert_geom_flags(args->flags);
166 pvr_fw_object_get_fw_addr(job->hwrt->fw_obj, &cmd->cmd_shared.hwrt_data_fw_addr);
167 return 0;
168 }
169
170 static int
pvr_frag_job_fw_cmd_init(struct pvr_job * job,struct drm_pvr_job * args)171 pvr_frag_job_fw_cmd_init(struct pvr_job *job,
172 struct drm_pvr_job *args)
173 {
174 struct rogue_fwif_cmd_frag *cmd;
175 int err;
176
177 if (args->flags & ~DRM_PVR_SUBMIT_JOB_FRAG_CMD_FLAGS_MASK)
178 return -EINVAL;
179
180 if (job->ctx->type != DRM_PVR_CTX_TYPE_RENDER)
181 return -EINVAL;
182
183 if (!job->hwrt)
184 return -EINVAL;
185
186 job->fw_ccb_cmd_type = (args->flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_PARTIAL_RENDER) ?
187 ROGUE_FWIF_CCB_CMD_TYPE_FRAG_PR :
188 ROGUE_FWIF_CCB_CMD_TYPE_FRAG;
189 err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_frag_stream,
190 args->cmd_stream, args->cmd_stream_len);
191 if (err)
192 return err;
193
194 cmd = job->cmd;
195 cmd->cmd_shared.cmn.frame_num = 0;
196 cmd->flags = convert_frag_flags(args->flags);
197 pvr_fw_object_get_fw_addr(job->hwrt->fw_obj, &cmd->cmd_shared.hwrt_data_fw_addr);
198 return 0;
199 }
200
201 static u32
convert_compute_flags(u32 in_flags)202 convert_compute_flags(u32 in_flags)
203 {
204 u32 out_flags = 0;
205
206 if (in_flags & DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_PREVENT_ALL_OVERLAP)
207 out_flags |= ROGUE_COMPUTE_FLAG_PREVENT_ALL_OVERLAP;
208 if (in_flags & DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_SINGLE_CORE)
209 out_flags |= ROGUE_COMPUTE_FLAG_SINGLE_CORE;
210
211 return out_flags;
212 }
213
214 static int
pvr_compute_job_fw_cmd_init(struct pvr_job * job,struct drm_pvr_job * args)215 pvr_compute_job_fw_cmd_init(struct pvr_job *job,
216 struct drm_pvr_job *args)
217 {
218 struct rogue_fwif_cmd_compute *cmd;
219 int err;
220
221 if (args->flags & ~DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_FLAGS_MASK)
222 return -EINVAL;
223
224 if (job->ctx->type != DRM_PVR_CTX_TYPE_COMPUTE)
225 return -EINVAL;
226
227 job->fw_ccb_cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_CDM;
228 err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_compute_stream,
229 args->cmd_stream, args->cmd_stream_len);
230 if (err)
231 return err;
232
233 cmd = job->cmd;
234 cmd->common.frame_num = 0;
235 cmd->flags = convert_compute_flags(args->flags);
236 return 0;
237 }
238
239 static u32
convert_transfer_flags(u32 in_flags)240 convert_transfer_flags(u32 in_flags)
241 {
242 u32 out_flags = 0;
243
244 if (in_flags & DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_SINGLE_CORE)
245 out_flags |= ROGUE_TRANSFER_FLAGS_SINGLE_CORE;
246
247 return out_flags;
248 }
249
250 static int
pvr_transfer_job_fw_cmd_init(struct pvr_job * job,struct drm_pvr_job * args)251 pvr_transfer_job_fw_cmd_init(struct pvr_job *job,
252 struct drm_pvr_job *args)
253 {
254 struct rogue_fwif_cmd_transfer *cmd;
255 int err;
256
257 if (args->flags & ~DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_FLAGS_MASK)
258 return -EINVAL;
259
260 if (job->ctx->type != DRM_PVR_CTX_TYPE_TRANSFER_FRAG)
261 return -EINVAL;
262
263 job->fw_ccb_cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_TQ_3D;
264 err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_transfer_stream,
265 args->cmd_stream, args->cmd_stream_len);
266 if (err)
267 return err;
268
269 cmd = job->cmd;
270 cmd->common.frame_num = 0;
271 cmd->flags = convert_transfer_flags(args->flags);
272 return 0;
273 }
274
275 static int
pvr_job_fw_cmd_init(struct pvr_job * job,struct drm_pvr_job * args)276 pvr_job_fw_cmd_init(struct pvr_job *job,
277 struct drm_pvr_job *args)
278 {
279 switch (args->type) {
280 case DRM_PVR_JOB_TYPE_GEOMETRY:
281 return pvr_geom_job_fw_cmd_init(job, args);
282
283 case DRM_PVR_JOB_TYPE_FRAGMENT:
284 return pvr_frag_job_fw_cmd_init(job, args);
285
286 case DRM_PVR_JOB_TYPE_COMPUTE:
287 return pvr_compute_job_fw_cmd_init(job, args);
288
289 case DRM_PVR_JOB_TYPE_TRANSFER_FRAG:
290 return pvr_transfer_job_fw_cmd_init(job, args);
291
292 default:
293 return -EINVAL;
294 }
295 }
296
297 /**
298 * struct pvr_job_data - Helper container for pairing jobs with the
299 * sync_ops supplied for them by the user.
300 */
301 struct pvr_job_data {
302 /** @job: Pointer to the job. */
303 struct pvr_job *job;
304
305 /** @sync_ops: Pointer to the sync_ops associated with @job. */
306 struct drm_pvr_sync_op *sync_ops;
307
308 /** @sync_op_count: Number of members of @sync_ops. */
309 u32 sync_op_count;
310 };
311
312 /**
313 * prepare_job_syncs() - Prepare all sync objects for a single job.
314 * @pvr_file: PowerVR file.
315 * @job_data: Precreated job and sync_ops array.
316 * @signal_array: xarray to receive signal sync objects.
317 *
318 * Returns:
319 * * 0 on success, or
320 * * Any error code returned by pvr_sync_signal_array_collect_ops(),
321 * pvr_sync_add_deps_to_job(), drm_sched_job_add_resv_dependencies() or
322 * pvr_sync_signal_array_update_fences().
323 */
324 static int
prepare_job_syncs(struct pvr_file * pvr_file,struct pvr_job_data * job_data,struct xarray * signal_array)325 prepare_job_syncs(struct pvr_file *pvr_file,
326 struct pvr_job_data *job_data,
327 struct xarray *signal_array)
328 {
329 struct dma_fence *done_fence;
330 int err = pvr_sync_signal_array_collect_ops(signal_array,
331 from_pvr_file(pvr_file),
332 job_data->sync_op_count,
333 job_data->sync_ops);
334
335 if (err)
336 return err;
337
338 err = pvr_sync_add_deps_to_job(pvr_file, &job_data->job->base,
339 job_data->sync_op_count,
340 job_data->sync_ops, signal_array);
341 if (err)
342 return err;
343
344 if (job_data->job->hwrt) {
345 /* The geometry job writes the HWRT region headers, which are
346 * then read by the fragment job.
347 */
348 struct drm_gem_object *obj =
349 gem_from_pvr_gem(job_data->job->hwrt->fw_obj->gem);
350 enum dma_resv_usage usage =
351 dma_resv_usage_rw(job_data->job->type ==
352 DRM_PVR_JOB_TYPE_GEOMETRY);
353
354 dma_resv_lock(obj->resv, NULL);
355 err = drm_sched_job_add_resv_dependencies(&job_data->job->base,
356 obj->resv, usage);
357 dma_resv_unlock(obj->resv);
358 if (err)
359 return err;
360 }
361
362 /* We need to arm the job to get the job done fence. */
363 done_fence = pvr_queue_job_arm(job_data->job);
364
365 err = pvr_sync_signal_array_update_fences(signal_array,
366 job_data->sync_op_count,
367 job_data->sync_ops,
368 done_fence);
369 return err;
370 }
371
372 /**
373 * prepare_job_syncs_for_each() - Prepare all sync objects for an array of jobs.
374 * @pvr_file: PowerVR file.
375 * @job_data: Array of precreated jobs and their sync_ops.
376 * @job_count: Number of jobs.
377 * @signal_array: xarray to receive signal sync objects.
378 *
379 * Returns:
380 * * 0 on success, or
381 * * Any error code returned by pvr_vm_bind_job_prepare_syncs().
382 */
383 static int
prepare_job_syncs_for_each(struct pvr_file * pvr_file,struct pvr_job_data * job_data,u32 * job_count,struct xarray * signal_array)384 prepare_job_syncs_for_each(struct pvr_file *pvr_file,
385 struct pvr_job_data *job_data,
386 u32 *job_count,
387 struct xarray *signal_array)
388 {
389 for (u32 i = 0; i < *job_count; i++) {
390 int err = prepare_job_syncs(pvr_file, &job_data[i],
391 signal_array);
392
393 if (err) {
394 *job_count = i;
395 return err;
396 }
397 }
398
399 return 0;
400 }
401
402 static struct pvr_job *
create_job(struct pvr_device * pvr_dev,struct pvr_file * pvr_file,struct drm_pvr_job * args)403 create_job(struct pvr_device *pvr_dev,
404 struct pvr_file *pvr_file,
405 struct drm_pvr_job *args)
406 {
407 struct pvr_job *job = NULL;
408 int err;
409
410 if (!args->cmd_stream || !args->cmd_stream_len)
411 return ERR_PTR(-EINVAL);
412
413 if (args->type != DRM_PVR_JOB_TYPE_GEOMETRY &&
414 args->type != DRM_PVR_JOB_TYPE_FRAGMENT &&
415 (args->hwrt.set_handle || args->hwrt.data_index))
416 return ERR_PTR(-EINVAL);
417
418 job = kzalloc(sizeof(*job), GFP_KERNEL);
419 if (!job)
420 return ERR_PTR(-ENOMEM);
421
422 kref_init(&job->ref_count);
423 job->type = args->type;
424 job->pvr_dev = pvr_dev;
425
426 err = xa_alloc(&pvr_dev->job_ids, &job->id, job, xa_limit_32b, GFP_KERNEL);
427 if (err)
428 goto err_put_job;
429
430 job->ctx = pvr_context_lookup(pvr_file, args->context_handle);
431 if (!job->ctx) {
432 err = -EINVAL;
433 goto err_put_job;
434 }
435
436 if (args->hwrt.set_handle) {
437 job->hwrt = pvr_hwrt_data_lookup(pvr_file, args->hwrt.set_handle,
438 args->hwrt.data_index);
439 if (!job->hwrt) {
440 err = -EINVAL;
441 goto err_put_job;
442 }
443 }
444
445 err = pvr_job_fw_cmd_init(job, args);
446 if (err)
447 goto err_put_job;
448
449 err = pvr_queue_job_init(job);
450 if (err)
451 goto err_put_job;
452
453 return job;
454
455 err_put_job:
456 pvr_job_put(job);
457 return ERR_PTR(err);
458 }
459
460 /**
461 * pvr_job_data_fini() - Cleanup all allocs used to set up job submission.
462 * @job_data: Job data array.
463 * @job_count: Number of members of @job_data.
464 */
465 static void
pvr_job_data_fini(struct pvr_job_data * job_data,u32 job_count)466 pvr_job_data_fini(struct pvr_job_data *job_data, u32 job_count)
467 {
468 for (u32 i = 0; i < job_count; i++) {
469 pvr_job_put(job_data[i].job);
470 kvfree(job_data[i].sync_ops);
471 }
472 }
473
474 /**
475 * pvr_job_data_init() - Init an array of created jobs, associating them with
476 * the appropriate sync_ops args, which will be copied in.
477 * @pvr_dev: Target PowerVR device.
478 * @pvr_file: Pointer to PowerVR file structure.
479 * @job_args: Job args array copied from user.
480 * @job_count: Number of members of @job_args.
481 * @job_data_out: Job data array.
482 */
pvr_job_data_init(struct pvr_device * pvr_dev,struct pvr_file * pvr_file,struct drm_pvr_job * job_args,u32 * job_count,struct pvr_job_data * job_data_out)483 static int pvr_job_data_init(struct pvr_device *pvr_dev,
484 struct pvr_file *pvr_file,
485 struct drm_pvr_job *job_args,
486 u32 *job_count,
487 struct pvr_job_data *job_data_out)
488 {
489 int err = 0, i = 0;
490
491 for (; i < *job_count; i++) {
492 job_data_out[i].job =
493 create_job(pvr_dev, pvr_file, &job_args[i]);
494 err = PTR_ERR_OR_ZERO(job_data_out[i].job);
495
496 if (err) {
497 *job_count = i;
498 job_data_out[i].job = NULL;
499 goto err_cleanup;
500 }
501
502 err = PVR_UOBJ_GET_ARRAY(job_data_out[i].sync_ops,
503 &job_args[i].sync_ops);
504 if (err) {
505 *job_count = i;
506
507 /* Ensure the job created above is also cleaned up. */
508 i++;
509 goto err_cleanup;
510 }
511
512 job_data_out[i].sync_op_count = job_args[i].sync_ops.count;
513 }
514
515 return 0;
516
517 err_cleanup:
518 pvr_job_data_fini(job_data_out, i);
519
520 return err;
521 }
522
523 static void
push_jobs(struct pvr_job_data * job_data,u32 job_count)524 push_jobs(struct pvr_job_data *job_data, u32 job_count)
525 {
526 for (u32 i = 0; i < job_count; i++)
527 pvr_queue_job_push(job_data[i].job);
528 }
529
530 static int
prepare_fw_obj_resv(struct drm_exec * exec,struct pvr_fw_object * fw_obj)531 prepare_fw_obj_resv(struct drm_exec *exec, struct pvr_fw_object *fw_obj)
532 {
533 return drm_exec_prepare_obj(exec, gem_from_pvr_gem(fw_obj->gem), 1);
534 }
535
536 static int
jobs_lock_all_objs(struct drm_exec * exec,struct pvr_job_data * job_data,u32 job_count)537 jobs_lock_all_objs(struct drm_exec *exec, struct pvr_job_data *job_data,
538 u32 job_count)
539 {
540 for (u32 i = 0; i < job_count; i++) {
541 struct pvr_job *job = job_data[i].job;
542
543 /* Grab a lock on a the context, to guard against
544 * concurrent submission to the same queue.
545 */
546 int err = drm_exec_lock_obj(exec,
547 gem_from_pvr_gem(job->ctx->fw_obj->gem));
548
549 if (err)
550 return err;
551
552 if (job->hwrt) {
553 err = prepare_fw_obj_resv(exec,
554 job->hwrt->fw_obj);
555 if (err)
556 return err;
557 }
558 }
559
560 return 0;
561 }
562
563 static int
prepare_job_resvs_for_each(struct drm_exec * exec,struct pvr_job_data * job_data,u32 job_count)564 prepare_job_resvs_for_each(struct drm_exec *exec, struct pvr_job_data *job_data,
565 u32 job_count)
566 {
567 drm_exec_until_all_locked(exec) {
568 int err = jobs_lock_all_objs(exec, job_data, job_count);
569
570 drm_exec_retry_on_contention(exec);
571 if (err)
572 return err;
573 }
574
575 return 0;
576 }
577
578 static void
update_job_resvs(struct pvr_job * job)579 update_job_resvs(struct pvr_job *job)
580 {
581 if (job->hwrt) {
582 enum dma_resv_usage usage = job->type == DRM_PVR_JOB_TYPE_GEOMETRY ?
583 DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ;
584 struct drm_gem_object *obj = gem_from_pvr_gem(job->hwrt->fw_obj->gem);
585
586 dma_resv_add_fence(obj->resv, &job->base.s_fence->finished, usage);
587 }
588 }
589
590 static void
update_job_resvs_for_each(struct pvr_job_data * job_data,u32 job_count)591 update_job_resvs_for_each(struct pvr_job_data *job_data, u32 job_count)
592 {
593 for (u32 i = 0; i < job_count; i++)
594 update_job_resvs(job_data[i].job);
595 }
596
can_combine_jobs(struct pvr_job * a,struct pvr_job * b)597 static bool can_combine_jobs(struct pvr_job *a, struct pvr_job *b)
598 {
599 struct pvr_job *geom_job = a, *frag_job = b;
600 struct dma_fence *fence;
601 unsigned long index;
602
603 /* Geometry and fragment jobs can be combined if they are queued to the
604 * same context and targeting the same HWRT.
605 */
606 if (a->type != DRM_PVR_JOB_TYPE_GEOMETRY ||
607 b->type != DRM_PVR_JOB_TYPE_FRAGMENT ||
608 a->ctx != b->ctx ||
609 a->hwrt != b->hwrt)
610 return false;
611
612 xa_for_each(&frag_job->base.dependencies, index, fence) {
613 /* We combine when we see an explicit geom -> frag dep. */
614 if (&geom_job->base.s_fence->scheduled == fence)
615 return true;
616 }
617
618 return false;
619 }
620
621 static struct dma_fence *
get_last_queued_job_scheduled_fence(struct pvr_queue * queue,struct pvr_job_data * job_data,u32 cur_job_pos)622 get_last_queued_job_scheduled_fence(struct pvr_queue *queue,
623 struct pvr_job_data *job_data,
624 u32 cur_job_pos)
625 {
626 /* We iterate over the current job array in reverse order to grab the
627 * last to-be-queued job targeting the same queue.
628 */
629 for (u32 i = cur_job_pos; i > 0; i--) {
630 struct pvr_job *job = job_data[i - 1].job;
631
632 if (job->ctx == queue->ctx && job->type == queue->type)
633 return dma_fence_get(&job->base.s_fence->scheduled);
634 }
635
636 /* If we didn't find any, we just return the last queued job scheduled
637 * fence attached to the queue.
638 */
639 return dma_fence_get(queue->last_queued_job_scheduled_fence);
640 }
641
642 static int
pvr_jobs_link_geom_frag(struct pvr_job_data * job_data,u32 * job_count)643 pvr_jobs_link_geom_frag(struct pvr_job_data *job_data, u32 *job_count)
644 {
645 for (u32 i = 0; i < *job_count - 1; i++) {
646 struct pvr_job *geom_job = job_data[i].job;
647 struct pvr_job *frag_job = job_data[i + 1].job;
648 struct pvr_queue *frag_queue;
649 struct dma_fence *f;
650
651 if (!can_combine_jobs(job_data[i].job, job_data[i + 1].job))
652 continue;
653
654 /* The fragment job will be submitted by the geometry queue. We
655 * need to make sure it comes after all the other fragment jobs
656 * queued before it.
657 */
658 frag_queue = pvr_context_get_queue_for_job(frag_job->ctx,
659 frag_job->type);
660 f = get_last_queued_job_scheduled_fence(frag_queue, job_data,
661 i);
662 if (f) {
663 int err = drm_sched_job_add_dependency(&geom_job->base,
664 f);
665 if (err) {
666 *job_count = i;
667 return err;
668 }
669 }
670
671 /* The KCCB slot will be reserved by the geometry job, so we can
672 * drop the KCCB fence on the fragment job.
673 */
674 pvr_kccb_fence_put(frag_job->kccb_fence);
675 frag_job->kccb_fence = NULL;
676
677 geom_job->paired_job = frag_job;
678 frag_job->paired_job = geom_job;
679
680 /* The geometry job pvr_job structure is used when the fragment
681 * job is being prepared by the GPU scheduler. Have the fragment
682 * job hold a reference on the geometry job to prevent it being
683 * freed until the fragment job has finished with it.
684 */
685 pvr_job_get(geom_job);
686
687 /* Skip the fragment job we just paired to the geometry job. */
688 i++;
689 }
690
691 return 0;
692 }
693
694 /**
695 * pvr_submit_jobs() - Submit jobs to the GPU
696 * @pvr_dev: Target PowerVR device.
697 * @pvr_file: Pointer to PowerVR file structure.
698 * @args: Ioctl args.
699 *
700 * This initial implementation is entirely synchronous; on return the GPU will
701 * be idle. This will not be the case for future implementations.
702 *
703 * Returns:
704 * * 0 on success,
705 * * -%EFAULT if arguments can not be copied from user space, or
706 * * -%EINVAL on invalid arguments, or
707 * * Any other error.
708 */
709 int
pvr_submit_jobs(struct pvr_device * pvr_dev,struct pvr_file * pvr_file,struct drm_pvr_ioctl_submit_jobs_args * args)710 pvr_submit_jobs(struct pvr_device *pvr_dev, struct pvr_file *pvr_file,
711 struct drm_pvr_ioctl_submit_jobs_args *args)
712 {
713 struct pvr_job_data *job_data = NULL;
714 struct drm_pvr_job *job_args;
715 struct xarray signal_array;
716 u32 jobs_alloced = 0;
717 struct drm_exec exec;
718 int err;
719
720 if (!args->jobs.count)
721 return -EINVAL;
722
723 err = PVR_UOBJ_GET_ARRAY(job_args, &args->jobs);
724 if (err)
725 return err;
726
727 job_data = kvmalloc_array(args->jobs.count, sizeof(*job_data),
728 GFP_KERNEL | __GFP_ZERO);
729 if (!job_data) {
730 err = -ENOMEM;
731 goto out_free;
732 }
733
734 err = pvr_job_data_init(pvr_dev, pvr_file, job_args, &args->jobs.count,
735 job_data);
736 if (err)
737 goto out_free;
738
739 jobs_alloced = args->jobs.count;
740
741 /*
742 * Flush MMU if needed - this has been deferred until now to avoid
743 * overuse of this expensive operation.
744 */
745 err = pvr_mmu_flush_exec(pvr_dev, false);
746 if (err)
747 goto out_job_data_cleanup;
748
749 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES, 0);
750
751 xa_init_flags(&signal_array, XA_FLAGS_ALLOC);
752
753 err = prepare_job_syncs_for_each(pvr_file, job_data, &args->jobs.count,
754 &signal_array);
755 if (err)
756 goto out_exec_fini;
757
758 err = prepare_job_resvs_for_each(&exec, job_data, args->jobs.count);
759 if (err)
760 goto out_exec_fini;
761
762 err = pvr_jobs_link_geom_frag(job_data, &args->jobs.count);
763 if (err)
764 goto out_exec_fini;
765
766 /* Anything after that point must succeed because we start exposing job
767 * finished fences to the outside world.
768 */
769 update_job_resvs_for_each(job_data, args->jobs.count);
770 push_jobs(job_data, args->jobs.count);
771 pvr_sync_signal_array_push_fences(&signal_array);
772 err = 0;
773
774 out_exec_fini:
775 drm_exec_fini(&exec);
776 pvr_sync_signal_array_cleanup(&signal_array);
777
778 out_job_data_cleanup:
779 pvr_job_data_fini(job_data, jobs_alloced);
780
781 out_free:
782 kvfree(job_data);
783 kvfree(job_args);
784
785 return err;
786 }
787