Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad1a58a4 authored by Christian König's avatar Christian König Committed by Alex Deucher
Browse files

drm/radeon: track VM update fences separately



Note for each fence if it's a VM page table update or not. This allows
us to determine the last VM update in a sync object and so to figure
out if we need to flush the TLB or not.

Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 587cdda8
Loading
Loading
Loading
Loading
+10 −8
Original line number Diff line number Diff line
@@ -366,6 +366,7 @@ struct radeon_fence {
	uint64_t		seq;
	/* RB, DMA, etc. */
	unsigned		ring;
	bool			is_vm_update;

	wait_queue_t		fence_wake;
};
@@ -594,6 +595,7 @@ void radeon_semaphore_free(struct radeon_device *rdev,
struct radeon_sync {
	struct radeon_semaphore *semaphores[RADEON_NUM_SYNCS];
	struct radeon_fence	*sync_to[RADEON_NUM_RINGS];
	struct radeon_fence	*last_vm_update;
};

void radeon_sync_create(struct radeon_sync *sync);
@@ -926,8 +928,8 @@ struct radeon_vm {
	struct mutex			mutex;
	/* last fence for cs using this vm */
	struct radeon_fence		*fence;
	/* last flush or NULL if we still need to flush */
	struct radeon_fence		*last_flush;
	/* last flushed PD/PT update */
	struct radeon_fence		*flushed_updates;
	/* last use of vmid */
	struct radeon_fence		*last_id_use;
};
@@ -2975,7 +2977,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
				       struct radeon_vm *vm, int ring);
void radeon_vm_flush(struct radeon_device *rdev,
                     struct radeon_vm *vm,
                     int ring);
		     int ring, struct radeon_fence *fence);
void radeon_vm_fence(struct radeon_device *rdev,
		     struct radeon_vm *vm,
		     struct radeon_fence *fence);
+1 −0
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@ int radeon_fence_emit(struct radeon_device *rdev,
	(*fence)->rdev = rdev;
	(*fence)->seq = seq;
	(*fence)->ring = ring;
	(*fence)->is_vm_update = false;
	fence_init(&(*fence)->base, &radeon_fence_ops,
		   &rdev->fence_queue.lock, rdev->fence_context + ring, seq);
	radeon_fence_ring_emit(rdev, ring, *fence);
+2 −1
Original line number Diff line number Diff line
@@ -154,7 +154,8 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
	}

	if (ib->vm)
		radeon_vm_flush(rdev, ib->vm, ib->ring);
		radeon_vm_flush(rdev, ib->vm, ib->ring,
				ib->sync.last_vm_update);

	if (const_ib) {
		radeon_ring_ib_execute(rdev, const_ib->ring, const_ib);
+7 −0
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ void radeon_sync_create(struct radeon_sync *sync)

	for (i = 0; i < RADEON_NUM_RINGS; ++i)
		sync->sync_to[i] = NULL;

	sync->last_vm_update = NULL;
}

/**
@@ -68,6 +70,11 @@ void radeon_sync_fence(struct radeon_sync *sync,

	other = sync->sync_to[fence->ring];
	sync->sync_to[fence->ring] = radeon_fence_later(fence, other);

	if (fence->is_vm_update) {
		other = sync->last_vm_update;
		sync->last_vm_update = radeon_fence_later(fence, other);
	}
}

/**
+13 −12
Original line number Diff line number Diff line
@@ -190,7 +190,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
		return NULL;

	/* we definately need to flush */
	radeon_fence_unref(&vm->last_flush);
	vm->pd_gpu_addr = ~0ll;

	/* skip over VMID 0, since it is the system VM */
	for (i = 1; i < rdev->vm_manager.nvm; ++i) {
@@ -228,6 +228,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
 * @rdev: radeon_device pointer
 * @vm: vm we want to flush
 * @ring: ring to use for flush
 * @updates: last vm update that is waited for
 *
 * Flush the vm (cayman+).
 *
@@ -235,13 +236,16 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
 */
void radeon_vm_flush(struct radeon_device *rdev,
		     struct radeon_vm *vm,
		     int ring)
		     int ring, struct radeon_fence *updates)
{
	uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory);

	/* if we can't remember our last VM flush then flush now! */
	if (!vm->last_flush || pd_addr != vm->pd_gpu_addr) {
	if (pd_addr != vm->pd_gpu_addr || !vm->flushed_updates ||
	    radeon_fence_is_earlier(vm->flushed_updates, updates)) {

		trace_radeon_vm_flush(pd_addr, ring, vm->id);
		radeon_fence_unref(&vm->flushed_updates);
		vm->flushed_updates = radeon_fence_ref(updates);
		vm->pd_gpu_addr = pd_addr;
		radeon_ring_vm_flush(rdev, &rdev->ring[ring],
				     vm->id, vm->pd_gpu_addr);
@@ -272,10 +276,6 @@ void radeon_vm_fence(struct radeon_device *rdev,

	radeon_fence_unref(&vm->last_id_use);
	vm->last_id_use = radeon_fence_ref(fence);

        /* we just flushed the VM, remember that */
        if (!vm->last_flush)
                vm->last_flush = radeon_fence_ref(fence);
}

/**
@@ -418,6 +418,7 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev,
	if (r)
		goto error_free;

	ib.fence->is_vm_update = true;
	radeon_bo_fence(bo, ib.fence, false);

error_free:
@@ -697,10 +698,10 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev,
			radeon_ib_free(rdev, &ib);
			return r;
		}
		ib.fence->is_vm_update = true;
		radeon_bo_fence(pd, ib.fence, false);
		radeon_fence_unref(&vm->fence);
		vm->fence = radeon_fence_ref(ib.fence);
		radeon_fence_unref(&vm->last_flush);
	}
	radeon_ib_free(rdev, &ib);

@@ -989,11 +990,11 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
		radeon_ib_free(rdev, &ib);
		return r;
	}
	ib.fence->is_vm_update = true;
	radeon_vm_fence_pts(vm, bo_va->it.start, bo_va->it.last + 1, ib.fence);
	radeon_fence_unref(&vm->fence);
	vm->fence = radeon_fence_ref(ib.fence);
	radeon_ib_free(rdev, &ib);
	radeon_fence_unref(&vm->last_flush);

	return 0;
}
@@ -1124,7 +1125,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
	vm->id = 0;
	vm->ib_bo_va = NULL;
	vm->fence = NULL;
	vm->last_flush = NULL;
	vm->flushed_updates = NULL;
	vm->last_id_use = NULL;
	mutex_init(&vm->mutex);
	vm->va = RB_ROOT;
@@ -1196,7 +1197,7 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
	radeon_bo_unref(&vm->page_directory);

	radeon_fence_unref(&vm->fence);
	radeon_fence_unref(&vm->last_flush);
	radeon_fence_unref(&vm->flushed_updates);
	radeon_fence_unref(&vm->last_id_use);

	mutex_destroy(&vm->mutex);