mirror of
https://github.com/torvalds/linux.git
synced 2024-12-03 09:31:26 +00:00
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: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
parent
724e6d3fe8
commit
29105ccc43
@ -4441,12 +4441,35 @@ i915_gem_evict_from_inactive_list(struct drm_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_gpu_idle(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
bool lists_empty;
|
||||
uint32_t seqno;
|
||||
|
||||
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 (lists_empty)
|
||||
return 0;
|
||||
|
||||
/* 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)
|
||||
return -ENOMEM;
|
||||
|
||||
return i915_wait_request(dev, seqno);
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_idle(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
uint32_t seqno, cur_seqno, last_seqno;
|
||||
int stuck, ret;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
@ -4455,115 +4478,36 @@ i915_gem_idle(struct drm_device *dev)
|
||||
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
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
|
||||
while (!list_empty(&dev_priv->mm.flushing_list)) {
|
||||
struct drm_gem_object *obj;
|
||||
uint32_t old_write_domain;
|
||||
|
||||
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);
|
||||
|
||||
trace_i915_gem_object_change_domain(obj,
|
||||
obj->read_domains,
|
||||
old_write_domain);
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user