summaryrefslogtreecommitdiff
path: root/shared-core/i915_irq.c
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2008-05-14 15:13:14 -0700
committerEric Anholt <eric@anholt.net>2008-05-22 22:00:21 -0700
commit5e662f90d1143de53db866e2b8a94f1bfbe5fc51 (patch)
tree07eff8ed2e6babe0af336b21c1da3b2e260e8bbd /shared-core/i915_irq.c
parentd6f796857780fc54641047e2aa4e7091376928eb (diff)
[gem] Release GEM buffers from work task scheduled from IRQ.
There are now 3 lists. Active is buffers currently in the ringbuffer. Flushing is not in the ringbuffer, but needs a flush before unbinding. Inactive is as before. This prevents object_free → unbind → wait_rendering → object_reference and a kernel oops about weird refcounting. This also avoids an synchronous extra flush and wait when freeing a buffer which had a write_domain set (such as a temporary rendered to and then from using the 2d engine). It will sit around on the flushing list until the appropriate flush gets emitted, or we need the GTT space for another operation.
Diffstat (limited to 'shared-core/i915_irq.c')
-rw-r--r--shared-core/i915_irq.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index b17e2408..02191316 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -436,6 +436,28 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
return count;
}
+/**
+ * Handler for user interrupts in process context (able to sleep, do VFS
+ * operations, etc.
+ *
+ * If another IRQ comes in while we're in this handler, it will still get put
+ * on the queue again to be rerun when we finish.
+ */
+void
+i915_user_interrupt_handler(struct work_struct *work)
+{
+ drm_i915_private_t *dev_priv;
+ struct drm_device *dev;
+
+ dev_priv = container_of(work, drm_i915_private_t,
+ user_interrupt_task);
+ dev = dev_priv->dev;
+
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_retire_requests(dev);
+ mutex_unlock(&dev->struct_mutex);
+}
+
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -493,6 +515,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
DRM_WAKEUP(&dev_priv->irq_queue);
#ifdef I915_HAVE_FENCE
i915_fence_handler(dev);
+ schedule_work(&dev_priv->user_interrupt_task);
#endif
}