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

drm/xe: Remove async worker and rework sync binds



Async worker is gone. All jobs and memory allocations done in IOCTL to
align with dma fencing rules.

Async vs. sync now means when do bind operations complete relative to
the IOCTL. Async completes when out-syncs signal while sync completes
when the IOCTL returns. In-syncs and out-syncs are only allowed in async
mode.

If memory allocations fail in the job creation step the VM is killed.
This is temporary, eventually a proper unwind will be done and VM will
be usable.

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 b21ae51d
Loading
Loading
Loading
Loading
+0 −43
Original line number Diff line number Diff line
@@ -196,27 +196,6 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
		}
	}

	/*
	 * We can't install a job into the VM dma-resv shared slot before an
	 * async VM bind passed in as a fence without the risk of deadlocking as
	 * the bind can trigger an eviction which in turn depends on anything in
	 * the VM dma-resv shared slots. Not an ideal solution, but we wait for
	 * all dependent async VM binds to start (install correct fences into
	 * dma-resv slots) before moving forward.
	 */
	if (!xe_vm_no_dma_fences(vm) &&
	    vm->flags & XE_VM_FLAG_ASYNC_BIND_OPS) {
		for (i = 0; i < args->num_syncs; i++) {
			struct dma_fence *fence = syncs[i].fence;

			if (fence) {
				err = xe_vm_async_fence_wait_start(fence);
				if (err)
					goto err_syncs;
			}
		}
	}

retry:
	if (!xe_vm_no_dma_fences(vm) && xe_vm_userptr_check_repin(vm)) {
		err = down_write_killable(&vm->lock);
@@ -229,28 +208,6 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
	if (err)
		goto err_syncs;

	/* We don't allow execs while the VM is in error state */
	if (vm->async_ops.error) {
		err = vm->async_ops.error;
		goto err_unlock_list;
	}

	/*
	 * Extreme corner where we exit a VM error state with a munmap style VM
	 * unbind inflight which requires a rebind. In this case the rebind
	 * needs to install some fences into the dma-resv slots. The worker to
	 * do this queued, let that worker make progress by dropping vm->lock,
	 * flushing the worker and retrying the exec.
	 */
	if (vm->async_ops.munmap_rebind_inflight) {
		if (write_locked)
			up_write(&vm->lock);
		else
			up_read(&vm->lock);
		flush_work(&vm->async_ops.work);
		goto retry;
	}

	if (write_locked) {
		err = xe_vm_userptr_pin(vm);
		downgrade_write(&vm->lock);
+6 −1
Original line number Diff line number Diff line
@@ -621,7 +621,10 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
	if (XE_IOCTL_DBG(xe, eci[0].gt_id >= xe->info.gt_count))
		return -EINVAL;

	if (eci[0].engine_class == DRM_XE_ENGINE_CLASS_VM_BIND) {
	if (eci[0].engine_class >= DRM_XE_ENGINE_CLASS_VM_BIND_ASYNC) {
		bool sync = eci[0].engine_class ==
			DRM_XE_ENGINE_CLASS_VM_BIND_SYNC;

		for_each_gt(gt, xe, id) {
			struct xe_exec_queue *new;

@@ -647,6 +650,8 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
						   args->width, hwe,
						   EXEC_QUEUE_FLAG_PERSISTENT |
						   EXEC_QUEUE_FLAG_VM |
						   (sync ? 0 :
						    EXEC_QUEUE_FLAG_VM_ASYNC) |
						   (id ?
						    EXEC_QUEUE_FLAG_BIND_ENGINE_CHILD :
						    0));
+2 −0
Original line number Diff line number Diff line
@@ -77,6 +77,8 @@ struct xe_exec_queue {
#define EXEC_QUEUE_FLAG_VM			BIT(4)
/* child of VM queue for multi-tile VM jobs */
#define EXEC_QUEUE_FLAG_BIND_ENGINE_CHILD	BIT(5)
/* VM jobs for this queue are asynchronous */
#define EXEC_QUEUE_FLAG_VM_ASYNC		BIT(6)

	/**
	 * @flags: flags for this exec queue, should statically setup aside from ban
+3 −11
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@
#include "xe_sched_job_types.h"

#define SYNC_FLAGS_TYPE_MASK 0x3
#define SYNC_FLAGS_FENCE_INSTALLED	0x10000

struct user_fence {
	struct xe_device *xe;
@@ -223,12 +222,11 @@ int xe_sync_entry_add_deps(struct xe_sync_entry *sync, struct xe_sched_job *job)
	return 0;
}

bool xe_sync_entry_signal(struct xe_sync_entry *sync, struct xe_sched_job *job,
void xe_sync_entry_signal(struct xe_sync_entry *sync, struct xe_sched_job *job,
			  struct dma_fence *fence)
{
	if (!(sync->flags & DRM_XE_SYNC_SIGNAL) ||
	    sync->flags & SYNC_FLAGS_FENCE_INSTALLED)
		return false;
	if (!(sync->flags & DRM_XE_SYNC_SIGNAL))
		return;

	if (sync->chain_fence) {
		drm_syncobj_add_point(sync->syncobj, sync->chain_fence,
@@ -260,12 +258,6 @@ bool xe_sync_entry_signal(struct xe_sync_entry *sync, struct xe_sched_job *job,
		job->user_fence.addr = sync->addr;
		job->user_fence.value = sync->timeline_value;
	}

	/* TODO: external BO? */

	sync->flags |= SYNC_FLAGS_FENCE_INSTALLED;

	return true;
}

void xe_sync_entry_cleanup(struct xe_sync_entry *sync)
+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
int xe_sync_entry_wait(struct xe_sync_entry *sync);
int xe_sync_entry_add_deps(struct xe_sync_entry *sync,
			   struct xe_sched_job *job);
bool xe_sync_entry_signal(struct xe_sync_entry *sync,
void xe_sync_entry_signal(struct xe_sync_entry *sync,
			  struct xe_sched_job *job,
			  struct dma_fence *fence);
void xe_sync_entry_cleanup(struct xe_sync_entry *sync);
Loading