aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_gem.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-01-07 05:39:13 -0500
committerEric Anholt <eric@anholt.net>2010-02-16 14:48:43 -0500
commit29105ccc43ead5a0179d04b1404611981e92e278 (patch)
tree1b6cf8f79d73e2ab17c7ab3d9a56e4784777681f /drivers/gpu/drm/i915/i915_gem.c
parent724e6d3fe8003c3f60bf404bf22e4e331327c596 (diff)
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>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem.c')
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c144
1 files changed, 44 insertions, 100 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index ec8a0d7ffa39..129ac36ddc58 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4441,129 +4441,73 @@ i915_gem_evict_from_inactive_list(struct drm_device *dev)
4441 return 0; 4441 return 0;
4442} 4442}
4443 4443
4444int 4444static int
4445i915_gem_idle(struct drm_device *dev) 4445i915_gpu_idle(struct drm_device *dev)
4446{ 4446{
4447 drm_i915_private_t *dev_priv = dev->dev_private; 4447 drm_i915_private_t *dev_priv = dev->dev_private;
4448 uint32_t seqno, cur_seqno, last_seqno; 4448 bool lists_empty;
4449 int stuck, ret; 4449 uint32_t seqno;
4450 4450
4451 mutex_lock(&dev->struct_mutex); 4451 spin_lock(&dev_priv->mm.active_list_lock);
4452 lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
4453 list_empty(&dev_priv->mm.active_list);
4454 spin_unlock(&dev_priv->mm.active_list_lock);
4452 4455
4453 if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) { 4456 if (lists_empty)
4454 mutex_unlock(&dev->struct_mutex);
4455 return 0; 4457 return 0;
4456 }
4457
4458 /* Hack! Don't let anybody do execbuf while we don't control the chip.
4459 * We need to replace this with a semaphore, or something.
4460 */
4461 dev_priv->mm.suspended = 1;
4462 del_timer(&dev_priv->hangcheck_timer);
4463
4464 /* Cancel the retire work handler, wait for it to finish if running
4465 */
4466 mutex_unlock(&dev->struct_mutex);
4467 cancel_delayed_work_sync(&dev_priv->mm.retire_work);
4468 mutex_lock(&dev->struct_mutex);
4469 4458
4470 i915_kernel_lost_context(dev); 4459 /* Flush everything onto the inactive list. */
4471
4472 /* Flush the GPU along with all non-CPU write domains
4473 */
4474 i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); 4460 i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
4475 seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); 4461 seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
4476 4462 if (seqno == 0)
4477 if (seqno == 0) {
4478 mutex_unlock(&dev->struct_mutex);
4479 return -ENOMEM; 4463 return -ENOMEM;
4480 }
4481
4482 dev_priv->mm.waiting_gem_seqno = seqno;
4483 last_seqno = 0;
4484 stuck = 0;
4485 for (;;) {
4486 cur_seqno = i915_get_gem_seqno(dev);
4487 if (i915_seqno_passed(cur_seqno, seqno))
4488 break;
4489 if (last_seqno == cur_seqno) {
4490 if (stuck++ > 100) {
4491 DRM_ERROR("hardware wedged\n");
4492 atomic_set(&dev_priv->mm.wedged, 1);
4493 DRM_WAKEUP(&dev_priv->irq_queue);
4494 break;
4495 }
4496 }
4497 msleep(10);
4498 last_seqno = cur_seqno;
4499 }
4500 dev_priv->mm.waiting_gem_seqno = 0;
4501
4502 i915_gem_retire_requests(dev);
4503
4504 spin_lock(&dev_priv->mm.active_list_lock);
4505 if (!atomic_read(&dev_priv->mm.wedged)) {
4506 /* Active and flushing should now be empty as we've
4507 * waited for a sequence higher than any pending execbuffer
4508 */
4509 WARN_ON(!list_empty(&dev_priv->mm.active_list));
4510 WARN_ON(!list_empty(&dev_priv->mm.flushing_list));
4511 /* Request should now be empty as we've also waited
4512 * for the last request in the list
4513 */
4514 WARN_ON(!list_empty(&dev_priv->mm.request_list));
4515 }
4516
4517 /* Empty the active and flushing lists to inactive. If there's
4518 * anything left at this point, it means that we're wedged and
4519 * nothing good's going to happen by leaving them there. So strip
4520 * the GPU domains and just stuff them onto inactive.
4521 */
4522 while (!list_empty(&dev_priv->mm.active_list)) {
4523 struct drm_gem_object *obj;
4524 uint32_t old_write_domain;
4525
4526 obj = list_first_entry(&dev_priv->mm.active_list,
4527 struct drm_i915_gem_object,
4528 list)->obj;
4529 old_write_domain = obj->write_domain;
4530 obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
4531 i915_gem_object_move_to_inactive(obj);
4532 4464
4533 trace_i915_gem_object_change_domain(obj, 4465 return i915_wait_request(dev, seqno);
4534 obj->read_domains, 4466}
4535 old_write_domain);
4536 }
4537 spin_unlock(&dev_priv->mm.active_list_lock);
4538 4467
4539 while (!list_empty(&dev_priv->mm.flushing_list)) { 4468int
4540 struct drm_gem_object *obj; 4469i915_gem_idle(struct drm_device *dev)
4541 uint32_t old_write_domain; 4470{
4471 drm_i915_private_t *dev_priv = dev->dev_private;
4472 int ret;
4542 4473
4543 obj = list_first_entry(&dev_priv->mm.flushing_list, 4474 mutex_lock(&dev->struct_mutex);
4544 struct drm_i915_gem_object,
4545 list)->obj;
4546 old_write_domain = obj->write_domain;
4547 obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
4548 i915_gem_object_move_to_inactive(obj);
4549 4475
4550 trace_i915_gem_object_change_domain(obj, 4476 if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) {
4551 obj->read_domains, 4477 mutex_unlock(&dev->struct_mutex);
4552 old_write_domain); 4478 return 0;
4553 } 4479 }
4554 4480
4555 4481 ret = i915_gpu_idle(dev);
4556 /* Move all inactive buffers out of the GTT. */
4557 ret = i915_gem_evict_from_inactive_list(dev);
4558 WARN_ON(!list_empty(&dev_priv->mm.inactive_list));
4559 if (ret) { 4482 if (ret) {
4560 mutex_unlock(&dev->struct_mutex); 4483 mutex_unlock(&dev->struct_mutex);
4561 return ret; 4484 return ret;
4562 } 4485 }
4563 4486
4487 /* Under UMS, be paranoid and evict. */
4488 if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
4489 ret = i915_gem_evict_from_inactive_list(dev);
4490 if (ret) {
4491 mutex_unlock(&dev->struct_mutex);
4492 return ret;
4493 }
4494 }
4495
4496 /* Hack! Don't let anybody do execbuf while we don't control the chip.
4497 * We need to replace this with a semaphore, or something.
4498 * And not confound mm.suspended!
4499 */
4500 dev_priv->mm.suspended = 1;
4501 del_timer(&dev_priv->hangcheck_timer);
4502
4503 i915_kernel_lost_context(dev);
4564 i915_gem_cleanup_ringbuffer(dev); 4504 i915_gem_cleanup_ringbuffer(dev);
4505
4565 mutex_unlock(&dev->struct_mutex); 4506 mutex_unlock(&dev->struct_mutex);
4566 4507
4508 /* Cancel the retire work handler, which should be idle now. */
4509 cancel_delayed_work_sync(&dev_priv->mm.retire_work);
4510
4567 return 0; 4511 return 0;
4568} 4512}
4569 4513