[Intel-gfx] s/obj->mm.lock//

Thomas Hellström (Intel) thomas_os at shipmail.org
Mon Jul 27 18:53:40 UTC 2020


On 7/6/20 8:19 AM, Chris Wilson wrote:
> This is the easy part; pulling reservation of multiple objects under an
> ww acquire context. With one simple rule that eviction is handled by the
> ww acquire context, we can carefully transition the driver over to using
> eviction. Instead of feeding the acquire context everywhere, we make the
> caller gather up all the objects they need to acquire into the context,
> then acquire their backing store. The major boon here is that by
> providing a clean set of objects (that we have not yet started to
> acquire any auxiliary attachments for) to the acquire context, it can
> handle all the EDEADLK processing for us [since it is a pure locking
> operation and does not need to release attachments upon revoking the
> locks].
>
> As a sketch of what that would look like, to illustrate the major work
> remaining:
>
> static int evict(struct drm_i915_gem_object *obj, struct i915_acquire_ctx *ctx)
> {
> 	struct intel_memory_region *mem = obj->mm->region;
> 	struct drm_i915_gem_object *swap; // struct i915_mm_bo *swap
> 	struct i915_request *rq;
> 	int err;
>
> 	/* swap = mem->create_eviction_target(obj); */
> 	swap = i915_gem_object_create_shmem(mem->i915, obj->base.size);
> 	if (IS_ERR(swap))
> 		return PTR_ERR(swap);
>
> 	err = dma_resv_lock_interruptible(swap, &ctx->ctx);
> 	GEM_BUG_ON(err == -EALREADY);
> 	if (err == -EDEADLK)
> 		goto out;
>
> 	/* Obviously swap has to be carefully chosen so that this may succeed */
> 	err = __i915_gem_object_get_pages_locked(swap);
> 	if (err)
> 		goto out_unlock;
>
> 	rq = pinned_evict_copy(ctx, obj, swap);
> 	if (IS_ERR(rq)) {
> 		err = PTR_ERR(rq);
> 		goto out_unlock;
> 	}
>
> 	err = i915_gem_revoke_mm(obj);
> 	if (err)
> 		goto out_request;
>
> 	/* Alternatively you could wait synchronously! */
> 	mem->release_blocks(&obj->mm->blocks, rq);
> 	i915_mm_bo_put(xchg(&obj->mm, i915_mm_bo_get(swap)));
>
> 	dma_resv_add_exclusive_fence(obj->base.resv, &rq->fence);
> out_request:
> 	i915_request_put(rq);
> out_unlock:
> 	dma_resv_unlock(swap);
> out:
> 	i915_gem_object_put(swap);
> 	return err;
> }
>
> static int relock_all(struct i915_acquire_ctx *ctx)
> {
> 	struct i915_acquire_link *lnk, *lock;
> 	int err;
>
> 	for (lnk = ctx->locked; lnk; lnk = lnk->next)
> 		dma_resv_unlock(lnk->obj->base.resv);
>
> 	lock = fetch_and_zero(&ctx->locked);
> 	while ((lnk = lock)) {
> 		struct drm_i915_gem_object *obj;
>
> 		obj = lnk->obj;
> 		lock = lnk->next;
>
> 		if (ctx->locked)
> 			err = dma_resv_lock_interruptible(obj->base.resv,
> 							  &ctx->ctx);
> 		else
> 			err = dma_resv_lock_slow_interruptible(obj->base.resv,
> 							       &ctx->ctx);
> 		GEM_BUG_ON(err == -EALREADY);
> 		if (err == -EDEADLK) {
> 			struct i915_acquire *old;
>
> 			while ((old = ctx->locked)) {
> 				dma_resv_unlock(old->obj->base.resv);
> 				ctx->locked = old->next;
> 				old->next = lock;
> 				lock = old;
> 			}
>
> 			lnk->next = lock;
> 			lock = lnk;
> 			continue;
> 		}
> 		if (err) {
> 			lock = lnk;
> 			break;
> 		}
>
> 		lnk->next = ctx->locked;
> 		ctx->locked = lnk;
> 	}
>
> 	while ((lnk = lock)) {
> 		lock = lnk->next;
> 		i915_gem_object_put(lnk->obj);
> 		i915_acquire_free(lnk);
> 	}
>
> 	return err;
> }
>
> int i915_acquire_mm(struct i915_acquire_ctx *ctx)
> {
> 	struct i915_acquire_link *lnk;
> 	int n, err;
>
> restart:
> 	for (lnk = ctx->locked; lnk; lnk = lnk->next) {
> 		for (n = 0;
> 		     !i915_gem_object_has_pages(lnk->obj);
> 		     n++) {
> 			struct drm_i915_gem_object *evictee = NULL;
>
> 			mem = get_preferred_memregion_for_object(lnk->obj, n);
> 			if (!mem)
> 				return -ENXIO;
>
> 			while (!i915_gem_object_get_pages(lnk->obj)) {
> 				struct i915_acquire_link *this;
>
> 				evictee = mem->get_eviction_candidate(mem,
> 								      evictee);
> 				if (!evictee)
> 					break;
>
> 				err = dma_resv_lock_interruptible(evictee,
> 								  &ctx->ctx);
> 				if (err == -EALREADY)
> 					continue; /* XXX fragmentation? */
> 				if (err == 0)
> 					err = evict(evictee);
> 				dma_resv_unlock(evictee);

There was a discussion on dri-devel not too long ago, where Christian 
mentioned there is a point holding on to the evictee(s) locks until  the 
get_pages() succeeds to avoid racing with threads wanting to move the 
evictee back into vram. Perhaps something worth considering.

/Thomas




More information about the Intel-gfx mailing list