aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2010-02-07 10:20:18 -0500
committerEric Anholt <eric@anholt.net>2010-02-10 16:31:45 -0500
commit99fcb766a3a50466fe31d743260a3400c1aee855 (patch)
tree1e3c929f781838b921acd41d281f796e9efe355b
parentb91ad0ec52770dcb622b94fc1f57e076686f427a (diff)
drm/i915: Update write_domains on active list after flush.
Before changing the status of a buffer with a pending write we will await upon a new flush for that buffer. So we can take advantage of any flushes posted whilst the buffer is active and pending processing by the GPU, by clearing its write_domain and updating its last_rendering_seqno -- thus saving a potential flush in deep queues and improves flushing behaviour upon eviction for both GTT space and fences. In order to reduce the time spent searching the active list for matching write_domains, we move those to a separate list whose elements are the buffers belong to the active/flushing list with pending writes. Orignal patch by Chris Wilson <chris@chris-wilson.co.uk>, forward-ported by me. In addition to better performance, this also fixes a real bug. Before this changes, i915_gem_evict_everything didn't work as advertised. When the gpu was actually busy and processing request, the flush and subsequent wait would not move active and dirty buffers to the inactive list, but just to the flushing list. Which triggered the BUG_ON at the end of this function. With the more tight dirty buffer tracking, all currently busy and dirty buffers get moved to the inactive list by one i915_gem_flush operation. I've left the BUG_ON I've used to prove this in there. References: Bug 25911 - 2.10.0 causes kernel oops and system hangs http://bugs.freedesktop.org/show_bug.cgi?id=25911 Bug 26101 - [i915] xf86-video-intel 2.10.0 (and git) triggers kernel oops within seconds after login http://bugs.freedesktop.org/show_bug.cgi?id=26101 Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Tested-by: Adam Lantos <hege@playma.org> Cc: stable@kernel.org Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h11
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c23
2 files changed, 30 insertions, 4 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index aaf934d96f21..b99b6a841d95 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -493,6 +493,15 @@ typedef struct drm_i915_private {
493 struct list_head flushing_list; 493 struct list_head flushing_list;
494 494
495 /** 495 /**
496 * List of objects currently pending a GPU write flush.
497 *
498 * All elements on this list will belong to either the
499 * active_list or flushing_list, last_rendering_seqno can
500 * be used to differentiate between the two elements.
501 */
502 struct list_head gpu_write_list;
503
504 /**
496 * LRU list of objects which are not in the ringbuffer and 505 * LRU list of objects which are not in the ringbuffer and
497 * are ready to unbind, but are still in the GTT. 506 * are ready to unbind, but are still in the GTT.
498 * 507 *
@@ -592,6 +601,8 @@ struct drm_i915_gem_object {
592 601
593 /** This object's place on the active/flushing/inactive lists */ 602 /** This object's place on the active/flushing/inactive lists */
594 struct list_head list; 603 struct list_head list;
604 /** This object's place on GPU write list */
605 struct list_head gpu_write_list;
595 606
596 /** This object's place on the fenced object LRU */ 607 /** This object's place on the fenced object LRU */
597 struct list_head fence_list; 608 struct list_head fence_list;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index b4c8c0230689..11daa618385f 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1552,6 +1552,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
1552 else 1552 else
1553 list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); 1553 list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
1554 1554
1555 BUG_ON(!list_empty(&obj_priv->gpu_write_list));
1556
1555 obj_priv->last_rendering_seqno = 0; 1557 obj_priv->last_rendering_seqno = 0;
1556 if (obj_priv->active) { 1558 if (obj_priv->active) {
1557 obj_priv->active = 0; 1559 obj_priv->active = 0;
@@ -1622,7 +1624,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
1622 struct drm_i915_gem_object *obj_priv, *next; 1624 struct drm_i915_gem_object *obj_priv, *next;
1623 1625
1624 list_for_each_entry_safe(obj_priv, next, 1626 list_for_each_entry_safe(obj_priv, next,
1625 &dev_priv->mm.flushing_list, list) { 1627 &dev_priv->mm.gpu_write_list,
1628 gpu_write_list) {
1626 struct drm_gem_object *obj = obj_priv->obj; 1629 struct drm_gem_object *obj = obj_priv->obj;
1627 1630
1628 if ((obj->write_domain & flush_domains) == 1631 if ((obj->write_domain & flush_domains) ==
@@ -1630,6 +1633,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
1630 uint32_t old_write_domain = obj->write_domain; 1633 uint32_t old_write_domain = obj->write_domain;
1631 1634
1632 obj->write_domain = 0; 1635 obj->write_domain = 0;
1636 list_del_init(&obj_priv->gpu_write_list);
1633 i915_gem_object_move_to_active(obj, seqno); 1637 i915_gem_object_move_to_active(obj, seqno);
1634 1638
1635 trace_i915_gem_object_change_domain(obj, 1639 trace_i915_gem_object_change_domain(obj,
@@ -2084,8 +2088,8 @@ static int
2084i915_gem_evict_everything(struct drm_device *dev) 2088i915_gem_evict_everything(struct drm_device *dev)
2085{ 2089{
2086 drm_i915_private_t *dev_priv = dev->dev_private; 2090 drm_i915_private_t *dev_priv = dev->dev_private;
2087 uint32_t seqno;
2088 int ret; 2091 int ret;
2092 uint32_t seqno;
2089 bool lists_empty; 2093 bool lists_empty;
2090 2094
2091 spin_lock(&dev_priv->mm.active_list_lock); 2095 spin_lock(&dev_priv->mm.active_list_lock);
@@ -2107,6 +2111,8 @@ i915_gem_evict_everything(struct drm_device *dev)
2107 if (ret) 2111 if (ret)
2108 return ret; 2112 return ret;
2109 2113
2114 BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
2115
2110 ret = i915_gem_evict_from_inactive_list(dev); 2116 ret = i915_gem_evict_from_inactive_list(dev);
2111 if (ret) 2117 if (ret)
2112 return ret; 2118 return ret;
@@ -2701,7 +2707,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
2701 old_write_domain = obj->write_domain; 2707 old_write_domain = obj->write_domain;
2702 i915_gem_flush(dev, 0, obj->write_domain); 2708 i915_gem_flush(dev, 0, obj->write_domain);
2703 seqno = i915_add_request(dev, NULL, obj->write_domain); 2709 seqno = i915_add_request(dev, NULL, obj->write_domain);
2704 obj->write_domain = 0; 2710 BUG_ON(obj->write_domain);
2705 i915_gem_object_move_to_active(obj, seqno); 2711 i915_gem_object_move_to_active(obj, seqno);
2706 2712
2707 trace_i915_gem_object_change_domain(obj, 2713 trace_i915_gem_object_change_domain(obj,
@@ -3850,16 +3856,23 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
3850 i915_gem_flush(dev, 3856 i915_gem_flush(dev,
3851 dev->invalidate_domains, 3857 dev->invalidate_domains,
3852 dev->flush_domains); 3858 dev->flush_domains);
3853 if (dev->flush_domains) 3859 if (dev->flush_domains & I915_GEM_GPU_DOMAINS)
3854 (void)i915_add_request(dev, file_priv, 3860 (void)i915_add_request(dev, file_priv,
3855 dev->flush_domains); 3861 dev->flush_domains);
3856 } 3862 }
3857 3863
3858 for (i = 0; i < args->buffer_count; i++) { 3864 for (i = 0; i < args->buffer_count; i++) {
3859 struct drm_gem_object *obj = object_list[i]; 3865 struct drm_gem_object *obj = object_list[i];
3866 struct drm_i915_gem_object *obj_priv = obj->driver_private;
3860 uint32_t old_write_domain = obj->write_domain; 3867 uint32_t old_write_domain = obj->write_domain;
3861 3868
3862 obj->write_domain = obj->pending_write_domain; 3869 obj->write_domain = obj->pending_write_domain;
3870 if (obj->write_domain)
3871 list_move_tail(&obj_priv->gpu_write_list,
3872 &dev_priv->mm.gpu_write_list);
3873 else
3874 list_del_init(&obj_priv->gpu_write_list);
3875
3863 trace_i915_gem_object_change_domain(obj, 3876 trace_i915_gem_object_change_domain(obj,
3864 obj->read_domains, 3877 obj->read_domains,
3865 old_write_domain); 3878 old_write_domain);
@@ -4370,6 +4383,7 @@ int i915_gem_init_object(struct drm_gem_object *obj)
4370 obj_priv->obj = obj; 4383 obj_priv->obj = obj;
4371 obj_priv->fence_reg = I915_FENCE_REG_NONE; 4384 obj_priv->fence_reg = I915_FENCE_REG_NONE;
4372 INIT_LIST_HEAD(&obj_priv->list); 4385 INIT_LIST_HEAD(&obj_priv->list);
4386 INIT_LIST_HEAD(&obj_priv->gpu_write_list);
4373 INIT_LIST_HEAD(&obj_priv->fence_list); 4387 INIT_LIST_HEAD(&obj_priv->fence_list);
4374 obj_priv->madv = I915_MADV_WILLNEED; 4388 obj_priv->madv = I915_MADV_WILLNEED;
4375 4389
@@ -4821,6 +4835,7 @@ i915_gem_load(struct drm_device *dev)
4821 spin_lock_init(&dev_priv->mm.active_list_lock); 4835 spin_lock_init(&dev_priv->mm.active_list_lock);
4822 INIT_LIST_HEAD(&dev_priv->mm.active_list); 4836 INIT_LIST_HEAD(&dev_priv->mm.active_list);
4823 INIT_LIST_HEAD(&dev_priv->mm.flushing_list); 4837 INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
4838 INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
4824 INIT_LIST_HEAD(&dev_priv->mm.inactive_list); 4839 INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
4825 INIT_LIST_HEAD(&dev_priv->mm.request_list); 4840 INIT_LIST_HEAD(&dev_priv->mm.request_list);
4826 INIT_LIST_HEAD(&dev_priv->mm.fence_list); 4841 INIT_LIST_HEAD(&dev_priv->mm.fence_list);