Skip to content

Commit

Permalink
drm/i915: Pull i915_vma_pin under the vm->mutex
Browse files Browse the repository at this point in the history
Replace the struct_mutex requirement for pinning the i915_vma with the
local vm->mutex instead. Note that the vm->mutex is tainted by the
shrinker (we require unbinding from inside fs-reclaim) and so we cannot
allocate while holding that mutex. Instead we have to preallocate
workers to do allocate and apply the PTE updates after we have we
reserved their slot in the drm_mm (using fences to order the PTE writes
with the GPU work and with later unbind).

In adding the asynchronous vma binding, one subtle requirement is to
avoid coupling the binding fence into the backing object->resv. That is
the asynchronous binding only applies to the vma timeline itself and not
to the pages as that is a more global timeline (the binding of one vma
does not need to be ordered with another vma, nor does the implicit GEM
fencing depend on a vma, only on writes to the backing store). Keeping
the vma binding distinct from the backing store timelines is verified by
a number of async gem_exec_fence and gem_exec_schedule tests. The way we
do this is quite simple, we keep the fence for the vma binding separate
and only wait on it as required, and never add it to the obj->resv
itself.

Another consequence in reducing the locking around the vma is the
destruction of the vma is no longer globally serialised by struct_mutex.
A natural solution would be to add a kref to i915_vma, but that requires
decoupling the reference cycles, possibly by introducing a new
i915_mm_pages object that is own by both obj->mm and vma->pages.
However, we have not taken that route due to the overshadowing lmem/ttm
discussions, and instead play a series of complicated games with
trylocks to (hopefully) ensure that only one destruction path is called!

v2: Add some commentary, and some helpers to reduce patch churn.

Signed-off-by: Chris Wilson <[email protected]>
Cc: Tvrtko Ursulin <[email protected]>
Reviewed-by: Tvrtko Ursulin <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  • Loading branch information
ickle committed Oct 4, 2019
1 parent 1133112 commit 2850748
Show file tree
Hide file tree
Showing 40 changed files with 824 additions and 706 deletions.
29 changes: 1 addition & 28 deletions drivers/gpu/drm/i915/display/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -2079,7 +2079,6 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
unsigned int pinctl;
u32 alignment;

WARN_ON(!mutex_is_locked(&dev->struct_mutex));
if (WARN_ON(!i915_gem_object_is_framebuffer(obj)))
return ERR_PTR(-EINVAL);

Expand Down Expand Up @@ -2163,8 +2162,6 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,

void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags)
{
lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);

i915_gem_object_lock(vma->obj);
if (flags & PLANE_HAS_FENCE)
i915_vma_unpin_fence(vma);
Expand Down Expand Up @@ -3065,12 +3062,10 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
return false;
}

mutex_lock(&dev->struct_mutex);
obj = i915_gem_object_create_stolen_for_preallocated(dev_priv,
base_aligned,
base_aligned,
size_aligned);
mutex_unlock(&dev->struct_mutex);
if (!obj)
return false;

Expand Down Expand Up @@ -3232,13 +3227,11 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
intel_state->color_plane[0].stride =
intel_fb_pitch(fb, 0, intel_state->base.rotation);

mutex_lock(&dev->struct_mutex);
intel_state->vma =
intel_pin_and_fence_fb_obj(fb,
&intel_state->view,
intel_plane_uses_fence(intel_state),
&intel_state->flags);
mutex_unlock(&dev->struct_mutex);
if (IS_ERR(intel_state->vma)) {
DRM_ERROR("failed to pin boot fb on pipe %d: %li\n",
intel_crtc->pipe, PTR_ERR(intel_state->vma));
Expand Down Expand Up @@ -14365,8 +14358,6 @@ static void fb_obj_bump_render_priority(struct drm_i915_gem_object *obj)
* bits. Some older platforms need special physical address handling for
* cursor planes.
*
* Must be called with struct_mutex held.
*
* Returns 0 on success, negative error code on failure.
*/
int
Expand Down Expand Up @@ -14423,15 +14414,8 @@ intel_prepare_plane_fb(struct drm_plane *plane,
if (ret)
return ret;

ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex);
if (ret) {
i915_gem_object_unpin_pages(obj);
return ret;
}

ret = intel_plane_pin_fb(to_intel_plane_state(new_state));

mutex_unlock(&dev_priv->drm.struct_mutex);
i915_gem_object_unpin_pages(obj);
if (ret)
return ret;
Expand Down Expand Up @@ -14480,8 +14464,6 @@ intel_prepare_plane_fb(struct drm_plane *plane,
* @old_state: the state from the previous modeset
*
* Cleans up a framebuffer that has just been removed from a plane.
*
* Must be called with struct_mutex held.
*/
void
intel_cleanup_plane_fb(struct drm_plane *plane,
Expand All @@ -14497,9 +14479,7 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
}

/* Should only be called after a successful intel_prepare_plane_fb()! */
mutex_lock(&dev_priv->drm.struct_mutex);
intel_plane_unpin_fb(to_intel_plane_state(old_state));
mutex_unlock(&dev_priv->drm.struct_mutex);
}

int
Expand Down Expand Up @@ -14702,7 +14682,6 @@ intel_legacy_cursor_update(struct drm_plane *plane,
u32 src_w, u32 src_h,
struct drm_modeset_acquire_ctx *ctx)
{
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
struct drm_plane_state *old_plane_state, *new_plane_state;
struct intel_plane *intel_plane = to_intel_plane(plane);
struct intel_crtc_state *crtc_state =
Expand Down Expand Up @@ -14768,13 +14747,9 @@ intel_legacy_cursor_update(struct drm_plane *plane,
if (ret)
goto out_free;

ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex);
if (ret)
goto out_free;

ret = intel_plane_pin_fb(to_intel_plane_state(new_plane_state));
if (ret)
goto out_unlock;
goto out_free;

intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_FLIP);
intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->fb),
Expand Down Expand Up @@ -14804,8 +14779,6 @@ intel_legacy_cursor_update(struct drm_plane *plane,

intel_plane_unpin_fb(to_intel_plane_state(old_plane_state));

out_unlock:
mutex_unlock(&dev_priv->drm.struct_mutex);
out_free:
if (new_crtc_state)
intel_crtc_destroy_state(crtc, &new_crtc_state->base);
Expand Down
7 changes: 1 addition & 6 deletions drivers/gpu/drm/i915/display/intel_dsb.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,7 @@ intel_dsb_get(struct intel_crtc *crtc)
goto err;
}

mutex_lock(&i915->drm.struct_mutex);
vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
mutex_unlock(&i915->drm.struct_mutex);
if (IS_ERR(vma)) {
DRM_ERROR("Vma creation failed\n");
i915_gem_object_put(obj);
Expand Down Expand Up @@ -164,10 +162,7 @@ void intel_dsb_put(struct intel_dsb *dsb)
return;

if (atomic_dec_and_test(&dsb->refcount)) {
mutex_lock(&i915->drm.struct_mutex);
i915_gem_object_unpin_map(dsb->vma->obj);
i915_vma_unpin_and_release(&dsb->vma, 0);
mutex_unlock(&i915->drm.struct_mutex);
i915_vma_unpin_and_release(&dsb->vma, I915_VMA_RELEASE_MAP);
dsb->cmd_buf = NULL;
dsb->free_pos = 0;
dsb->ins_start_offset = 0;
Expand Down
8 changes: 1 addition & 7 deletions drivers/gpu/drm/i915/display/intel_fbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
sizes->fb_height = intel_fb->base.height;
}

mutex_lock(&dev->struct_mutex);
wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);

/* Pin the GGTT vma for our access via info->screen_base.
Expand Down Expand Up @@ -266,15 +265,13 @@ static int intelfb_create(struct drm_fb_helper *helper,
ifbdev->vma_flags = flags;

intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
mutex_unlock(&dev->struct_mutex);
vga_switcheroo_client_fb_set(pdev, info);
return 0;

out_unpin:
intel_unpin_fb_vma(vma, flags);
out_unlock:
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
mutex_unlock(&dev->struct_mutex);
return ret;
}

Expand All @@ -291,11 +288,8 @@ static void intel_fbdev_destroy(struct intel_fbdev *ifbdev)

drm_fb_helper_fini(&ifbdev->helper);

if (ifbdev->vma) {
mutex_lock(&ifbdev->helper.dev->struct_mutex);
if (ifbdev->vma)
intel_unpin_fb_vma(ifbdev->vma, ifbdev->vma_flags);
mutex_unlock(&ifbdev->helper.dev->struct_mutex);
}

if (ifbdev->fb)
drm_framebuffer_remove(&ifbdev->fb->base);
Expand Down
11 changes: 2 additions & 9 deletions drivers/gpu/drm/i915/display/intel_overlay.c
Original file line number Diff line number Diff line change
Expand Up @@ -1303,15 +1303,11 @@ static int get_registers(struct intel_overlay *overlay, bool use_phys)
struct i915_vma *vma;
int err;

mutex_lock(&i915->drm.struct_mutex);

obj = i915_gem_object_create_stolen(i915, PAGE_SIZE);
if (obj == NULL)
obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
if (IS_ERR(obj)) {
err = PTR_ERR(obj);
goto err_unlock;
}
if (IS_ERR(obj))
return PTR_ERR(obj);

vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
if (IS_ERR(vma)) {
Expand All @@ -1332,13 +1328,10 @@ static int get_registers(struct intel_overlay *overlay, bool use_phys)
}

overlay->reg_bo = obj;
mutex_unlock(&i915->drm.struct_mutex);
return 0;

err_put_bo:
i915_gem_object_put(obj);
err_unlock:
mutex_unlock(&i915->drm.struct_mutex);
return err;
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/gem/i915_gem_client_blt.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ static void clear_pages_worker(struct work_struct *work)
* keep track of the GPU activity within this vma/request, and
* propagate the signal from the request to w->dma.
*/
err = i915_active_add_request(&vma->active, rq);
err = __i915_vma_move_to_active(vma, rq);
if (err)
goto out_request;

Expand Down
20 changes: 11 additions & 9 deletions drivers/gpu/drm/i915/gem/i915_gem_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,6 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
GEM_BUG_ON(!i915_gem_context_is_closed(ctx));

release_hw_id(ctx);
if (ctx->vm)
i915_vm_put(ctx->vm);

free_engines(rcu_access_pointer(ctx->engines));
mutex_destroy(&ctx->engines_mutex);
Expand Down Expand Up @@ -379,9 +377,13 @@ void i915_gem_context_release(struct kref *ref)

static void context_close(struct i915_gem_context *ctx)
{
i915_gem_context_set_closed(ctx);

if (ctx->vm)
i915_vm_close(ctx->vm);

mutex_lock(&ctx->mutex);

i915_gem_context_set_closed(ctx);
ctx->file_priv = ERR_PTR(-EBADF);

/*
Expand Down Expand Up @@ -474,7 +476,7 @@ __set_ppgtt(struct i915_gem_context *ctx, struct i915_address_space *vm)

GEM_BUG_ON(old && i915_vm_is_4lvl(vm) != i915_vm_is_4lvl(old));

ctx->vm = i915_vm_get(vm);
ctx->vm = i915_vm_open(vm);
context_apply_all(ctx, __apply_ppgtt, vm);

return old;
Expand All @@ -488,7 +490,7 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,

vm = __set_ppgtt(ctx, vm);
if (vm)
i915_vm_put(vm);
i915_vm_close(vm);
}

static void __set_timeline(struct intel_timeline **dst,
Expand Down Expand Up @@ -953,7 +955,7 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
if (ret < 0)
goto err_unlock;

i915_vm_get(vm);
i915_vm_open(vm);

args->size = 0;
args->value = ret;
Expand All @@ -973,7 +975,7 @@ static void set_ppgtt_barrier(void *data)
if (INTEL_GEN(old->i915) < 8)
gen6_ppgtt_unpin_all(i915_vm_to_ppgtt(old));

i915_vm_put(old);
i915_vm_close(old);
}

static int emit_ppgtt_update(struct i915_request *rq, void *data)
Expand Down Expand Up @@ -1090,8 +1092,8 @@ static int set_ppgtt(struct drm_i915_file_private *file_priv,
set_ppgtt_barrier,
old);
if (err) {
i915_vm_put(__set_ppgtt(ctx, old));
i915_vm_put(old);
i915_vm_close(__set_ppgtt(ctx, old));
i915_vm_close(old);
}

unlock:
Expand Down
13 changes: 7 additions & 6 deletions drivers/gpu/drm/i915/gem/i915_gem_domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,12 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
if (!drm_mm_node_allocated(&vma->node))
continue;

ret = i915_vma_bind(vma, cache_level, PIN_UPDATE);
/* Wait for an earlier async bind, need to rewrite it */
ret = i915_vma_sync(vma);
if (ret)
return ret;

ret = i915_vma_bind(vma, cache_level, PIN_UPDATE, NULL);
if (ret)
return ret;
}
Expand Down Expand Up @@ -391,16 +396,11 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
if (ret)
goto out;

ret = mutex_lock_interruptible(&i915->drm.struct_mutex);
if (ret)
goto out;

ret = i915_gem_object_lock_interruptible(obj);
if (ret == 0) {
ret = i915_gem_object_set_cache_level(obj, level);
i915_gem_object_unlock(obj);
}
mutex_unlock(&i915->drm.struct_mutex);

out:
i915_gem_object_put(obj);
Expand Down Expand Up @@ -485,6 +485,7 @@ static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj)
if (!drm_mm_node_allocated(&vma->node))
continue;

GEM_BUG_ON(vma->vm != &i915->ggtt.vm);
list_move_tail(&vma->vm_link, &vma->vm->bound_list);
}
mutex_unlock(&i915->ggtt.vm.mutex);
Expand Down
Loading

0 comments on commit 2850748

Please sign in to comment.