|
@@ -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;
|
|
|
}
|
|
|
|