Skip to content

Commit

Permalink
drm/i915: Gracefully handle obj not bound to GGTT in is_pin_display
Browse files Browse the repository at this point in the history
Otherwise, we do a NULL pointer dereference.

I've seen this happen while handling an error in
i915_gem_object_pin_to_display_plane():

If i915_gem_object_set_cache_level() fails, we call is_pin_display()
to handle the error. At this point, the object is still not pinned
to GGTT and maybe not even bound, so we have to check before we
dereference its GGTT vma.

The IGT kms_flip/bo-too-big tests for this bug.

v2: Chris Wilson says restoring the old value is easier, but that
is_pin_display is useful as a theory of operation. Take the solomonic
decision: at least this way is_pin_display is a little more robust
(until Chris can kill it off).

v3: Chris suggests the WARN in i915_gem_obj_to_ggtt has outlived its
usefulness: add a reminder to remove it.

Issue: VIZ-3772
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
Testcase: igt/kms_flip/bo-too-big
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Oscar Mateo authored and Daniel Vetter committed May 16, 2014
1 parent 4271b75 commit 1965643
Showing 1 changed file with 17 additions and 2 deletions.
19 changes: 17 additions & 2 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -3641,6 +3641,15 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,

static bool is_pin_display(struct drm_i915_gem_object *obj)
{
struct i915_vma *vma;

if (list_empty(&obj->vma_list))
return false;

vma = i915_gem_obj_to_ggtt(obj);
if (!vma)
return false;

/* There are 3 sources that pin objects:
* 1. The display engine (scanouts, sprites, cursors);
* 2. Reservations for execbuffer;
Expand All @@ -3652,7 +3661,7 @@ static bool is_pin_display(struct drm_i915_gem_object *obj)
* subtracting the potential reference by the user, any pin_count
* remains, it must be due to another use by the display engine.
*/
return i915_gem_obj_to_ggtt(obj)->pin_count - !!obj->user_pin_count;
return vma->pin_count - !!obj->user_pin_count;
}

/*
Expand All @@ -3666,6 +3675,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *pipelined)
{
u32 old_read_domains, old_write_domain;
bool was_pin_display;
int ret;

if (pipelined != obj->ring) {
Expand All @@ -3677,6 +3687,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
/* Mark the pin_display early so that we account for the
* display coherency whilst setting up the cache domains.
*/
was_pin_display = obj->pin_display;
obj->pin_display = true;

/* The display engine is not coherent with the LLC cache on gen6. As
Expand Down Expand Up @@ -3719,7 +3730,8 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
return 0;

err_unpin_display:
obj->pin_display = is_pin_display(obj);
WARN_ON(was_pin_display != is_pin_display(obj));
obj->pin_display = was_pin_display;
return ret;
}

Expand Down Expand Up @@ -5115,6 +5127,9 @@ struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
{
struct i915_vma *vma;

/* This WARN has probably outlived its usefulness (callers already
* WARN if they don't find the GGTT vma they expect). When removing,
* remember to remove the pre-check in is_pin_display() as well */
if (WARN_ON(list_empty(&obj->vma_list)))
return NULL;

Expand Down

0 comments on commit 1965643

Please sign in to comment.