Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+44 −100
Original line number Diff line number Diff line
@@ -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;
			}
	return i915_wait_request(dev, seqno);
}
		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;
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.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);
	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;
	}
	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);
	ret = i915_gpu_idle(dev);
	if (ret) {
		mutex_unlock(&dev->struct_mutex);
		return ret;
	}


	/* Move all inactive buffers out of the GTT. */
	/* Under UMS, be paranoid and evict. */
	if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
		ret = i915_gem_evict_from_inactive_list(dev);
	WARN_ON(!list_empty(&dev_priv->mm.inactive_list));
		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;
}