drm/i915: Replace open-coded eviction in i915_gem_idle()
authorChris Wilson <chris@chris-wilson.co.uk>
Thu, 7 Jan 2010 10:39:13 +0000 (10:39 +0000)
committerEric Anholt <eric@anholt.net>
Tue, 16 Feb 2010 19:48:43 +0000 (11:48 -0800)
With the introduction of the hang-check, we can safely expect that
i915_wait_request() will always return even when the GPU hangs, and so
do not need to open code the wait in order to manually check for the
hang. Also we do not need to always evict all buffers, so only flush
the GPU (and wait for it to idle) for KMS, but continue to evict for UMS.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Eric Anholt <eric@anholt.net>
drivers/gpu/drm/i915/i915_gem.c

index ec8a0d7ffa3990ea9f7ded8871f3ff384b2bf24d..129ac36ddc58437730eb540d63acd72a84a5e4c7 100644 (file)
@@ -4441,129 +4441,73 @@ i915_gem_evict_from_inactive_list(struct drm_device *dev)
        return 0;
 }
 
-int
-i915_gem_idle(struct drm_device *dev)
+static int
+i915_gpu_idle(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       uint32_t seqno, cur_seqno, last_seqno;
-       int stuck, ret;
+       bool lists_empty;
+       uint32_t seqno;
 
-       mutex_lock(&dev->struct_mutex);
+       spin_lock(&dev_priv->mm.active_list_lock);
+       lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
+                     list_empty(&dev_priv->mm.active_list);
+       spin_unlock(&dev_priv->mm.active_list_lock);
 
-       if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) {
-               mutex_unlock(&dev->struct_mutex);
+       if (lists_empty)
                return 0;
-       }
-
-       /* Hack!  Don't let anybody do execbuf while we don't control the chip.
-        * We need to replace this with a semaphore, or something.
-        */
-       dev_priv->mm.suspended = 1;
-       del_timer(&dev_priv->hangcheck_timer);
-
-       /* Cancel the retire work handler, wait for it to finish if running
-        */
-       mutex_unlock(&dev->struct_mutex);
-       cancel_delayed_work_sync(&dev_priv->mm.retire_work);
-       mutex_lock(&dev->struct_mutex);
 
-       i915_kernel_lost_context(dev);
-
-       /* Flush the GPU along with all non-CPU write domains
-        */
+       /* Flush everything onto the inactive list. */
        i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
        seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
-
-       if (seqno == 0) {
-               mutex_unlock(&dev->struct_mutex);
+       if (seqno == 0)
                return -ENOMEM;
-       }
-
-       dev_priv->mm.waiting_gem_seqno = seqno;
-       last_seqno = 0;
-       stuck = 0;
-       for (;;) {
-               cur_seqno = i915_get_gem_seqno(dev);
-               if (i915_seqno_passed(cur_seqno, seqno))
-                       break;
-               if (last_seqno == cur_seqno) {
-                       if (stuck++ > 100) {
-                               DRM_ERROR("hardware wedged\n");
-                               atomic_set(&dev_priv->mm.wedged, 1);
-                               DRM_WAKEUP(&dev_priv->irq_queue);
-                               break;
-                       }
-               }
-               msleep(10);
-               last_seqno = cur_seqno;
-       }
-       dev_priv->mm.waiting_gem_seqno = 0;
-
-       i915_gem_retire_requests(dev);
-
-       spin_lock(&dev_priv->mm.active_list_lock);
-       if (!atomic_read(&dev_priv->mm.wedged)) {
-               /* Active and flushing should now be empty as we've
-                * waited for a sequence higher than any pending execbuffer
-                */
-               WARN_ON(!list_empty(&dev_priv->mm.active_list));
-               WARN_ON(!list_empty(&dev_priv->mm.flushing_list));
-               /* Request should now be empty as we've also waited
-                * for the last request in the list
-                */
-               WARN_ON(!list_empty(&dev_priv->mm.request_list));
-       }
-
-       /* Empty the active and flushing lists to inactive.  If there's
-        * anything left at this point, it means that we're wedged and
-        * nothing good's going to happen by leaving them there.  So strip
-        * the GPU domains and just stuff them onto inactive.
-        */
-       while (!list_empty(&dev_priv->mm.active_list)) {
-               struct drm_gem_object *obj;
-               uint32_t old_write_domain;
-
-               obj = list_first_entry(&dev_priv->mm.active_list,
-                                      struct drm_i915_gem_object,
-                                      list)->obj;
-               old_write_domain = obj->write_domain;
-               obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
-               i915_gem_object_move_to_inactive(obj);
 
-               trace_i915_gem_object_change_domain(obj,
-                                                   obj->read_domains,
-                                                   old_write_domain);
-       }
-       spin_unlock(&dev_priv->mm.active_list_lock);
+       return i915_wait_request(dev, seqno);
+}
 
-       while (!list_empty(&dev_priv->mm.flushing_list)) {
-               struct drm_gem_object *obj;
-               uint32_t old_write_domain;
+int
+i915_gem_idle(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
 
-               obj = list_first_entry(&dev_priv->mm.flushing_list,
-                                      struct drm_i915_gem_object,
-                                      list)->obj;
-               old_write_domain = obj->write_domain;
-               obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
-               i915_gem_object_move_to_inactive(obj);
+       mutex_lock(&dev->struct_mutex);
 
-               trace_i915_gem_object_change_domain(obj,
-                                                   obj->read_domains,
-                                                   old_write_domain);
+       if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) {
+               mutex_unlock(&dev->struct_mutex);
+               return 0;
        }
 
-
-       /* Move all inactive buffers out of the GTT. */
-       ret = i915_gem_evict_from_inactive_list(dev);
-       WARN_ON(!list_empty(&dev_priv->mm.inactive_list));
+       ret = i915_gpu_idle(dev);
        if (ret) {
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
 
+       /* Under UMS, be paranoid and evict. */
+       if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
+               ret = i915_gem_evict_from_inactive_list(dev);
+               if (ret) {
+                       mutex_unlock(&dev->struct_mutex);
+                       return ret;
+               }
+       }
+
+       /* Hack!  Don't let anybody do execbuf while we don't control the chip.
+        * We need to replace this with a semaphore, or something.
+        * And not confound mm.suspended!
+        */
+       dev_priv->mm.suspended = 1;
+       del_timer(&dev_priv->hangcheck_timer);
+
+       i915_kernel_lost_context(dev);
        i915_gem_cleanup_ringbuffer(dev);
+
        mutex_unlock(&dev->struct_mutex);
 
+       /* Cancel the retire work handler, which should be idle now. */
+       cancel_delayed_work_sync(&dev_priv->mm.retire_work);
+
        return 0;
 }