summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/drm_irq.c1
-rw-r--r--linux-core/i915_gem.c29
-rw-r--r--shared-core/i915_dma.c5
-rw-r--r--shared-core/i915_drv.h12
4 files changed, 47 insertions, 0 deletions
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 8f27d7f3..318d9d7a 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -124,6 +124,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
(unsigned long)dev);
+ init_timer_deferrable(&dev->vblank_disable_timer);
spin_lock_init(&dev->vbl_lock);
atomic_set(&dev->vbl_signal_pending, 0);
dev->num_crtcs = num_crtcs;
diff --git a/linux-core/i915_gem.c b/linux-core/i915_gem.c
index 14e57b41..abc929e9 100644
--- a/linux-core/i915_gem.c
+++ b/linux-core/i915_gem.c
@@ -162,6 +162,9 @@ i915_add_request(struct drm_device *dev, uint32_t flush_domains)
request->seqno = seqno;
request->emitted_jiffies = jiffies;
request->flush_domains = flush_domains;
+ if (list_empty(&dev_priv->mm.request_list))
+ mod_timer(&dev_priv->mm.retire_timer, jiffies + HZ);
+
list_add_tail(&request->list, &dev_priv->mm.request_list);
return seqno;
@@ -300,6 +303,32 @@ i915_gem_retire_requests(struct drm_device *dev)
}
}
+void
+i915_gem_retire_timeout(unsigned long data)
+{
+ struct drm_device *dev = (struct drm_device *) data;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ schedule_work(&dev_priv->mm.retire_task);
+}
+
+void
+i915_gem_retire_handler(struct work_struct *work)
+{
+ drm_i915_private_t *dev_priv;
+ struct drm_device *dev;
+
+ dev_priv = container_of(work, drm_i915_private_t,
+ mm.retire_task);
+ dev = dev_priv->dev;
+
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_retire_requests(dev);
+ if (!list_empty(&dev_priv->mm.request_list))
+ mod_timer(&dev_priv->mm.retire_timer, jiffies + HZ);
+ mutex_unlock(&dev->struct_mutex);
+}
+
/**
* Waits for a sequence number to be signaled, and cleans up the
* request and object lists appropriately for that event.
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index c0ddeae0..f6465bf6 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -1078,6 +1078,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
INIT_LIST_HEAD(&dev_priv->mm.request_list);
+ dev_priv->mm.retire_timer.function = i915_gem_retire_timeout;
+ dev_priv->mm.retire_timer.data = (unsigned long) dev;
+ init_timer_deferrable (&dev_priv->mm.retire_timer);
+ INIT_WORK(&dev_priv->mm.retire_task,
+ i915_gem_retire_handler);
INIT_WORK(&dev_priv->user_interrupt_task,
i915_user_interrupt_handler);
dev_priv->mm.next_gem_seqno = 1;
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 33fb7ca9..55af6552 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -280,6 +280,16 @@ typedef struct drm_i915_private {
*/
struct list_head request_list;
+ /**
+ * We leave the user IRQ off as much as possible,
+ * but this means that requests will finish and never
+ * be retired once the system goes idle. Set a timer to
+ * fire periodically while the ring is running. When it
+ * fires, go retire requests.
+ */
+ struct timer_list retire_timer;
+ struct work_struct retire_task;
+
uint32_t next_gem_seqno;
} mm;
@@ -463,6 +473,8 @@ int i915_gem_flush_pwrite(struct drm_gem_object *obj,
uint64_t offset, uint64_t size);
void i915_gem_lastclose(struct drm_device *dev);
void i915_gem_retire_requests(struct drm_device *dev);
+void i915_gem_retire_timeout(unsigned long data);
+void i915_gem_retire_handler(struct work_struct *work);
#endif
#ifdef __linux__