Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 23static 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 */
 45void
 46pvr_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 */
 67static int
 68pvr_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
 86static 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
103static u32
104convert_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
118static u32
119convert_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
141static int
142pvr_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
170static int
171pvr_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
201static u32
202convert_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
214static int
215pvr_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
239static u32
240convert_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
250static int
251pvr_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
275static int
276pvr_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 */
301struct 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 */
324static int
325prepare_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 */
383static int
384prepare_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
402static struct pvr_job *
403create_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
455err_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 */
465static void
466pvr_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 */
483static 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
517err_cleanup:
518	pvr_job_data_fini(job_data_out, i);
519
520	return err;
521}
522
523static void
524push_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
530static int
531prepare_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
536static int
537jobs_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
563static int
564prepare_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
578static void
579update_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
590static void
591update_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
597static 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
621static struct dma_fence *
622get_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
642static int
643pvr_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		/* Skip the fragment job we just paired to the geometry job. */
681		i++;
682	}
683
684	return 0;
685}
686
687/**
688 * pvr_submit_jobs() - Submit jobs to the GPU
689 * @pvr_dev: Target PowerVR device.
690 * @pvr_file: Pointer to PowerVR file structure.
691 * @args: Ioctl args.
692 *
693 * This initial implementation is entirely synchronous; on return the GPU will
694 * be idle. This will not be the case for future implementations.
695 *
696 * Returns:
697 *  * 0 on success,
698 *  * -%EFAULT if arguments can not be copied from user space, or
699 *  * -%EINVAL on invalid arguments, or
700 *  * Any other error.
701 */
702int
703pvr_submit_jobs(struct pvr_device *pvr_dev, struct pvr_file *pvr_file,
704		struct drm_pvr_ioctl_submit_jobs_args *args)
705{
706	struct pvr_job_data *job_data = NULL;
707	struct drm_pvr_job *job_args;
708	struct xarray signal_array;
709	u32 jobs_alloced = 0;
710	struct drm_exec exec;
711	int err;
712
713	if (!args->jobs.count)
714		return -EINVAL;
715
716	err = PVR_UOBJ_GET_ARRAY(job_args, &args->jobs);
717	if (err)
718		return err;
719
720	job_data = kvmalloc_array(args->jobs.count, sizeof(*job_data),
721				  GFP_KERNEL | __GFP_ZERO);
722	if (!job_data) {
723		err = -ENOMEM;
724		goto out_free;
725	}
726
727	err = pvr_job_data_init(pvr_dev, pvr_file, job_args, &args->jobs.count,
728				job_data);
729	if (err)
730		goto out_free;
731
732	jobs_alloced = args->jobs.count;
733
734	/*
735	 * Flush MMU if needed - this has been deferred until now to avoid
736	 * overuse of this expensive operation.
737	 */
738	err = pvr_mmu_flush_exec(pvr_dev, false);
739	if (err)
740		goto out_job_data_cleanup;
741
742	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES, 0);
743
744	xa_init_flags(&signal_array, XA_FLAGS_ALLOC);
745
746	err = prepare_job_syncs_for_each(pvr_file, job_data, &args->jobs.count,
747					 &signal_array);
748	if (err)
749		goto out_exec_fini;
750
751	err = prepare_job_resvs_for_each(&exec, job_data, args->jobs.count);
752	if (err)
753		goto out_exec_fini;
754
755	err = pvr_jobs_link_geom_frag(job_data, &args->jobs.count);
756	if (err)
757		goto out_exec_fini;
758
759	/* Anything after that point must succeed because we start exposing job
760	 * finished fences to the outside world.
761	 */
762	update_job_resvs_for_each(job_data, args->jobs.count);
763	push_jobs(job_data, args->jobs.count);
764	pvr_sync_signal_array_push_fences(&signal_array);
765	err = 0;
766
767out_exec_fini:
768	drm_exec_fini(&exec);
769	pvr_sync_signal_array_cleanup(&signal_array);
770
771out_job_data_cleanup:
772	pvr_job_data_fini(job_data, jobs_alloced);
773
774out_free:
775	kvfree(job_data);
776	kvfree(job_args);
777
778	return err;
779}