Commit 29105ccc authored by Chris Wilson's avatar Chris Wilson Committed by Eric Anholt

drm/i915: Replace open-coded eviction in i915_gem_idle()

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: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent 724e6d3f
...@@ -4441,129 +4441,73 @@ i915_gem_evict_from_inactive_list(struct drm_device *dev) ...@@ -4441,129 +4441,73 @@ i915_gem_evict_from_inactive_list(struct drm_device *dev)
return 0; return 0;
} }
int static int
i915_gem_idle(struct drm_device *dev) i915_gpu_idle(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t seqno, cur_seqno, last_seqno; bool lists_empty;
int stuck, ret; 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) { if (lists_empty)
mutex_unlock(&dev->struct_mutex);
return 0; 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 everything onto the inactive list. */
/* Flush the GPU along with all non-CPU write domains
*/
i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
if (seqno == 0)
if (seqno == 0) {
mutex_unlock(&dev->struct_mutex);
return -ENOMEM; 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, return i915_wait_request(dev, seqno);
obj->read_domains, }
old_write_domain);
}
spin_unlock(&dev_priv->mm.active_list_lock);
while (!list_empty(&dev_priv->mm.flushing_list)) { int
struct drm_gem_object *obj; i915_gem_idle(struct drm_device *dev)
uint32_t old_write_domain; {
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
obj = list_first_entry(&dev_priv->mm.flushing_list, mutex_lock(&dev->struct_mutex);
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, if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) {
obj->read_domains, mutex_unlock(&dev->struct_mutex);
old_write_domain); return 0;
} }
ret = i915_gpu_idle(dev);
/* 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));
if (ret) { if (ret) {
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return ret; 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); i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex); 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; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment