drm/i915: Skip unbinding large unmappable global buffers
authorChris Wilson <chris@chris-wilson.co.uk>
Thu, 13 Oct 2016 08:55:04 +0000 (09:55 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Thu, 13 Oct 2016 14:47:47 +0000 (15:47 +0100)
If the user requests a mappable binding to the global GTT, we will first
unbind an existing mapping if it doesn't match. We will unbind even if
there is no possibility that the object can fit in the mappable
aperture. This may lead to a ping-pong migration of the object, for
example igt/gem_exec_big.

v2: Comment upon the reasoning, or lack thereof!, behind the choice of
magic numbers.

Testcase: igt/gem_exec_big
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/20161013085504.30705-1-chris@chris-wilson.co.uk
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com
drivers/gpu/drm/i915/i915_gem.c

index 830df36ca14cea69f25f3f8789c0dd586ee95fbf..77dc0590ecc7ebf2a196eb96eb2685253dec100b 100644 (file)
@@ -3100,6 +3100,9 @@ search_free:
 
                        goto err_unpin;
                }
+
+               GEM_BUG_ON(vma->node.start < start);
+               GEM_BUG_ON(vma->node.start + vma->node.size > end);
        }
        GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level));
 
@@ -3798,7 +3801,8 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
                         u64 alignment,
                         u64 flags)
 {
-       struct i915_address_space *vm = &to_i915(obj->base.dev)->ggtt.base;
+       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
+       struct i915_address_space *vm = &dev_priv->ggtt.base;
        struct i915_vma *vma;
        int ret;
 
@@ -3811,6 +3815,41 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
                    (i915_vma_is_pinned(vma) || i915_vma_is_active(vma)))
                        return ERR_PTR(-ENOSPC);
 
+               if (flags & PIN_MAPPABLE) {
+                       u32 fence_size;
+
+                       fence_size = i915_gem_get_ggtt_size(dev_priv, vma->size,
+                                                           i915_gem_object_get_tiling(obj));
+                       /* If the required space is larger than the available
+                        * aperture, we will not able to find a slot for the
+                        * object and unbinding the object now will be in
+                        * vain. Worse, doing so may cause us to ping-pong
+                        * the object in and out of the Global GTT and
+                        * waste a lot of cycles under the mutex.
+                        */
+                       if (fence_size > dev_priv->ggtt.mappable_end)
+                               return ERR_PTR(-E2BIG);
+
+                       /* If NONBLOCK is set the caller is optimistically
+                        * trying to cache the full object within the mappable
+                        * aperture, and *must* have a fallback in place for
+                        * situations where we cannot bind the object. We
+                        * can be a little more lax here and use the fallback
+                        * more often to avoid costly migrations of ourselves
+                        * and other objects within the aperture.
+                        *
+                        * Half-the-aperture is used as a simple heuristic.
+                        * More interesting would to do search for a free
+                        * block prior to making the commitment to unbind.
+                        * That caters for the self-harm case, and with a
+                        * little more heuristics (e.g. NOFAULT, NOEVICT)
+                        * we could try to minimise harm to others.
+                        */
+                       if (flags & PIN_NONBLOCK &&
+                           fence_size > dev_priv->ggtt.mappable_end / 2)
+                               return ERR_PTR(-ENOSPC);
+               }
+
                WARN(i915_vma_is_pinned(vma),
                     "bo is already pinned in ggtt with incorrect alignment:"
                     " offset=%08x, req.alignment=%llx,"