|
@@ -33,21 +33,20 @@
|
|
|
#include "intel_drv.h"
|
|
|
#include "i915_trace.h"
|
|
|
|
|
|
-static bool ggtt_is_idle(struct drm_i915_private *dev_priv)
|
|
|
+static bool ggtt_is_idle(struct drm_i915_private *i915)
|
|
|
{
|
|
|
- struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
|
|
- struct intel_engine_cs *engine;
|
|
|
- enum intel_engine_id id;
|
|
|
+ struct intel_engine_cs *engine;
|
|
|
+ enum intel_engine_id id;
|
|
|
|
|
|
- for_each_engine(engine, dev_priv, id) {
|
|
|
- struct intel_timeline *tl;
|
|
|
+ if (i915->gt.active_requests)
|
|
|
+ return false;
|
|
|
|
|
|
- tl = &ggtt->base.timeline.engine[engine->id];
|
|
|
- if (i915_gem_active_isset(&tl->last_request))
|
|
|
- return false;
|
|
|
- }
|
|
|
+ for_each_engine(engine, i915, id) {
|
|
|
+ if (engine->last_retired_context != i915->kernel_context)
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- return true;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
static int ggtt_flush(struct drm_i915_private *i915)
|
|
@@ -157,7 +156,8 @@ i915_gem_evict_something(struct i915_address_space *vm,
|
|
|
min_size, alignment, cache_level,
|
|
|
start, end, mode);
|
|
|
|
|
|
- /* Retire before we search the active list. Although we have
|
|
|
+ /*
|
|
|
+ * Retire before we search the active list. Although we have
|
|
|
* reasonable accuracy in our retirement lists, we may have
|
|
|
* a stray pin (preventing eviction) that can only be resolved by
|
|
|
* retiring.
|
|
@@ -182,7 +182,8 @@ search_again:
|
|
|
BUG_ON(ret);
|
|
|
}
|
|
|
|
|
|
- /* Can we unpin some objects such as idle hw contents,
|
|
|
+ /*
|
|
|
+ * Can we unpin some objects such as idle hw contents,
|
|
|
* or pending flips? But since only the GGTT has global entries
|
|
|
* such as scanouts, rinbuffers and contexts, we can skip the
|
|
|
* purge when inspecting per-process local address spaces.
|
|
@@ -190,19 +191,33 @@ search_again:
|
|
|
if (!i915_is_ggtt(vm) || flags & PIN_NONBLOCK)
|
|
|
return -ENOSPC;
|
|
|
|
|
|
- if (ggtt_is_idle(dev_priv)) {
|
|
|
- /* If we still have pending pageflip completions, drop
|
|
|
- * back to userspace to give our workqueues time to
|
|
|
- * acquire our locks and unpin the old scanouts.
|
|
|
- */
|
|
|
- return intel_has_pending_fb_unpin(dev_priv) ? -EAGAIN : -ENOSPC;
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * Not everything in the GGTT is tracked via VMA using
|
|
|
+ * i915_vma_move_to_active(), otherwise we could evict as required
|
|
|
+ * with minimal stalling. Instead we are forced to idle the GPU and
|
|
|
+ * explicitly retire outstanding requests which will then remove
|
|
|
+ * the pinning for active objects such as contexts and ring,
|
|
|
+ * enabling us to evict them on the next iteration.
|
|
|
+ *
|
|
|
+ * To ensure that all user contexts are evictable, we perform
|
|
|
+ * a switch to the perma-pinned kernel context. This all also gives
|
|
|
+ * us a termination condition, when the last retired context is
|
|
|
+ * the kernel's there is no more we can evict.
|
|
|
+ */
|
|
|
+ if (!ggtt_is_idle(dev_priv)) {
|
|
|
+ ret = ggtt_flush(dev_priv);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
- ret = ggtt_flush(dev_priv);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
+ goto search_again;
|
|
|
+ }
|
|
|
|
|
|
- goto search_again;
|
|
|
+ /*
|
|
|
+ * If we still have pending pageflip completions, drop
|
|
|
+ * back to userspace to give our workqueues time to
|
|
|
+ * acquire our locks and unpin the old scanouts.
|
|
|
+ */
|
|
|
+ return intel_has_pending_fb_unpin(dev_priv) ? -EAGAIN : -ENOSPC;
|
|
|
|
|
|
found:
|
|
|
/* drm_mm doesn't allow any other other operations while
|