Commit eb9702ad authored by Matthew Brost's avatar Matthew Brost Committed by Rodrigo Vivi
Browse files

drm/xe: Allow num_batch_buffer / num_binds == 0 in IOCTLs



The idea being out-syncs can signal indicating all previous operations
on the bind queue are complete. An example use case of this would be
support for implementing vkQueueWaitIdle easily.

All in-syncs are waited on before signaling out-syncs. This is
implemented by forming a composite software fence of in-syncs and
installing this fence in the out-syncs and exec queue last fence slot.

The last fence must be added as a dependency for jobs on user exec
queues as it is possible for the last fence to be a composite software
fence (unordered, ioctl with zero bb or binds) rather than hardware
fence (ordered, previous job on queue).

Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Signed-off-by: default avatarMatthew Brost <matthew.brost@intel.com>
Reviewed-by: default avatarThomas Hellström <thomas.hellstrom@linux.intel.com>
Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent f5783b50
Loading
Loading
Loading
Loading
+26 −1
Original line number Diff line number Diff line
@@ -131,7 +131,8 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
	if (XE_IOCTL_DBG(xe, q->flags & EXEC_QUEUE_FLAG_VM))
		return -EINVAL;

	if (XE_IOCTL_DBG(xe, q->width != args->num_batch_buffer))
	if (XE_IOCTL_DBG(xe, args->num_batch_buffer &&
			 q->width != args->num_batch_buffer))
		return -EINVAL;

	if (XE_IOCTL_DBG(xe, q->flags & EXEC_QUEUE_FLAG_BANNED)) {
@@ -207,6 +208,24 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
		goto err_exec;
	}

	if (!args->num_batch_buffer) {
		if (!xe_vm_in_lr_mode(vm)) {
			struct dma_fence *fence;

			fence = xe_sync_in_fence_get(syncs, num_syncs, q, vm);
			if (IS_ERR(fence)) {
				err = PTR_ERR(fence);
				goto err_exec;
			}
			for (i = 0; i < num_syncs; i++)
				xe_sync_entry_signal(&syncs[i], NULL, fence);
			xe_exec_queue_last_fence_set(q, vm, fence);
			dma_fence_put(fence);
		}

		goto err_exec;
	}

	if (xe_exec_queue_is_lr(q) && xe_exec_queue_ring_full(q)) {
		err = -EWOULDBLOCK;
		goto err_exec;
@@ -266,6 +285,10 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
		goto err_put_job;

	if (!xe_vm_in_lr_mode(vm)) {
		err = xe_sched_job_last_fence_add_dep(job, vm);
		if (err)
			goto err_put_job;

		err = down_read_interruptible(&vm->userptr.notifier_lock);
		if (err)
			goto err_put_job;
@@ -290,6 +313,8 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)

	if (xe_exec_queue_is_lr(q))
		q->ring_ops->emit_job(job);
	if (!xe_vm_in_lr_mode(vm))
		xe_exec_queue_last_fence_set(q, vm, &job->drm.s_fence->finished);
	xe_sched_job_push(job);
	xe_vm_reactivate_rebind(vm);

+4 −1
Original line number Diff line number Diff line
@@ -886,7 +886,10 @@ int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data,
static void xe_exec_queue_last_fence_lockdep_assert(struct xe_exec_queue *q,
						    struct xe_vm *vm)
{
	lockdep_assert_held_write(&vm->lock);
	if (q->flags & EXEC_QUEUE_FLAG_VM)
		lockdep_assert_held(&vm->lock);
	else
		xe_vm_assert_held(vm);
}

/**
+3 −2
Original line number Diff line number Diff line
@@ -66,8 +66,9 @@ struct xe_exec_queue {
	struct xe_hw_fence_irq *fence_irq;

	/**
	 * @last_fence: last fence on engine, protected by vm->lock in write
	 * mode if bind engine
	 * @last_fence: last fence on exec queue, protected by vm->lock in write
	 * mode if bind exec queue, protected by dma resv lock if non-bind exec
	 * queue
	 */
	struct dma_fence *last_fence;

+11 −3
Original line number Diff line number Diff line
@@ -1163,17 +1163,24 @@ xe_migrate_update_pgtables_cpu(struct xe_migrate *m,
	return fence;
}

static bool no_in_syncs(struct xe_sync_entry *syncs, u32 num_syncs)
static bool no_in_syncs(struct xe_vm *vm, struct xe_exec_queue *q,
			struct xe_sync_entry *syncs, u32 num_syncs)
{
	struct dma_fence *fence;
	int i;

	for (i = 0; i < num_syncs; i++) {
		struct dma_fence *fence = syncs[i].fence;
		fence = syncs[i].fence;

		if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
				       &fence->flags))
			return false;
	}
	if (q) {
		fence = xe_exec_queue_last_fence_get(q, vm);
		if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
			return false;
	}

	return true;
}
@@ -1234,7 +1241,7 @@ xe_migrate_update_pgtables(struct xe_migrate *m,
	u16 pat_index = xe->pat.idx[XE_CACHE_WB];

	/* Use the CPU if no in syncs and engine is idle */
	if (no_in_syncs(syncs, num_syncs) && xe_exec_queue_is_idle(q_override)) {
	if (no_in_syncs(vm, q, syncs, num_syncs) && xe_exec_queue_is_idle(q_override)) {
		fence =  xe_migrate_update_pgtables_cpu(m, vm, bo, updates,
							num_updates,
							first_munmap_rebind,
@@ -1351,6 +1358,7 @@ xe_migrate_update_pgtables(struct xe_migrate *m,
			goto err_job;
	}

	err = xe_sched_job_last_fence_add_dep(job, vm);
	for (i = 0; !err && i < num_syncs; i++)
		err = xe_sync_entry_add_deps(&syncs[i], job);

+18 −0
Original line number Diff line number Diff line
@@ -260,3 +260,21 @@ void xe_sched_job_push(struct xe_sched_job *job)
	drm_sched_entity_push_job(&job->drm);
	xe_sched_job_put(job);
}

/**
 * xe_sched_job_last_fence_add_dep - Add last fence dependency to job
 * @job:job to add the last fence dependency to
 * @vm: virtual memory job belongs to
 *
 * Returns:
 * 0 on success, or an error on failing to expand the array.
 */
int xe_sched_job_last_fence_add_dep(struct xe_sched_job *job, struct xe_vm *vm)
{
	struct dma_fence *fence;

	fence = xe_exec_queue_last_fence_get(job->q, vm);
	dma_fence_get(fence);

	return drm_sched_job_add_dependency(&job->drm, fence);
}
Loading