[Intel-gfx] [PATCH] drm/i915: Update write_domains on active list after flush.

Chris Wilson chris at chris-wilson.co.uk
Sun Jan 31 16:55:10 CET 2010


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.

Also as Daniel Vetter pointed out, currently we need to emit a flush and
wait on that flush *twice* in order to properly evict everything. The
first flush will just move dirty buffers onto the flushing list,
requiring the second, redundant, flush to finally move those onto the
inactive list.  The lack of the additional flush in
i915_gem_evict_everything() and i915_gpu_idle() will trigger BUGs, such
as:

[1400539.466422] [drm:i915_gem_object_pin] *ERROR* Failure to install fence: -28
[1400539.480213] [drm:i915_gem_object_pin] *ERROR* Failure to install fence: -28
[1400539.500195] [drm:i915_gem_object_pin] *ERROR* Failure to install fence: -28
[1400539.541957] ------------[ cut here ]------------
[1400539.541971] kernel BUG at
/tmp/buildd/linux-2.6-2.6.32/debian/build/source_i386_none/drivers/gpu/drm/i915/i915_gem.c:2123!
[1400539.541977] invalid opcode: 0000 [#1] SMP
[1400539.541982] last sysfs file:
/sys/devices/pci0000:00/0000:00:1e.0/0000:02:04.0/class
[1400539.541986] Modules linked in: i915 drm_kms_helper drm i2c_algo_bit
i2c_core ufs qnx4 hfsplus hfs minix ntfs vfat msdos fat jfs xfs exportfs
reiserfs ext3 jbd ext2 nfs lockd fscache nfs_acl auth_rpcgss sunrpc loop
joydev snd_intel8x0m snd_intel8x0 snd_ac97_codec snd_pcsp ac97_bus
snd_pcm yenta_socket snd_timer rsrc_nonstatic snd shpchp soundcore
psmouse dcdbas rng_core serio_raw snd_page_alloc pci_hotplug battery ac
evdev processor ext4 mbcache jbd2 crc16 ide_cd_mod ide_gd_mod cdrom
ide_pci_generic ata_generic libata scsi_mod uhci_hcd b44 ssb mmc_core
pcmcia piix pcmcia_core intel_agp mii ehci_hcd ide_core usbcore nls_base
agpgart button video output thermal fan thermal_sys [last unloaded:
scsi_wait_scan]
[1400539.542074]
[1400539.542080] Pid: 23623, comm: X Not tainted (2.6.32-trunk-686 #1) Inspiron 1100
[1400539.542085] EIP: 0060:[<d0c29202>] EFLAGS: 00213246 CPU: 0
[1400539.542106] EIP is at i915_gem_evict_everything+0xf1/0xfe [i915]
[1400539.542111] EAX: 00000000 EBX: cf74e000 ECX: cfbbd388 EDX: 0000dede
[1400539.542115] ESI: 00000000 EDI: cf9f5400 EBP: cf74ee0c ESP: cf9ffdf8
[1400539.542119]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
[1400539.542125] Process X (pid: 23623, ti=cf9fe000 task=ce250cc0 task.ti=cf9fe000)
[1400539.542128] Stack:
[1400539.542130]  cf74ee0c cf74ee20 00000022 00000022 ffffffe4 cf9f3360 d0c2a3e3 ccfcfe00
[1400539.542140] <0> c5a2bcc0 cf9ffe94 cf9f5400 cf74e000 cf9f5414 c36e7000 ced63a00 00000000
[1400539.542150] <0> d2fc5000 00000022 00000000 00000000 01c90073 bf930134 00000000 cf74e000
[1400539.542160] Call Trace:
[1400539.542174]  [<d0c2a3e3>] ? i915_gem_execbuffer+0x677/0xcc3 [i915]
[1400539.542187]  [<d08a05c3>] ? drm_ioctl+0x1d2/0x268 [drm]
[1400539.542199]  [<d0c29d6c>] ? i915_gem_execbuffer+0x0/0xcc3 [i915]
[1400539.542212]  [<c10bc24d>] ? vfs_ioctl+0x49/0x5f
[1400539.542218]  [<c10bc7b4>] ? do_vfs_ioctl+0x4aa/0x4e5
[1400539.542225]  [<c1259c36>] ? schedule+0x78f/0x7dc
[1400539.542233]  [<c1002cf7>] ? restore_sigcontext+0xbe/0xd5
[1400539.542239]  [<c10bc830>] ? sys_ioctl+0x41/0x58
[1400539.542245]  [<c10030fb>] ? sysenter_do_call+0x12/0x28
[1400539.542248] Code: 0e 00 00 39 83 18 0e 00 00 75 14 8d 83 10 0e 00
00 39 83 10 0e 00 00 0f 94 c0 0f b6 c0 eb 02 31 c0 fe 83 0c 0e 00 00 85
c0 75 04 <0f> 0b eb fe 5d 89 f0 5a 5b 5e 5f 5d c3 55 83 3d 44 c6 c4 d0
00
[1400539.542297] EIP: [<d0c29202>] i915_gem_evict_everything+0xf1/0xfe [i915] SS:ESP 0068:cf9ffdf8
[1400539.542314] ---[ end trace 2e3c5b62fd2600b8 ]---

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: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
Cc: stable at kernel.org
---
 drivers/gpu/drm/i915/i915_drv.h |   11 +++++++++++
 drivers/gpu/drm/i915/i915_gem.c |   37 +++++++++++++++++++------------------
 2 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 6d9f83c..fc1a1a1 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -494,6 +494,15 @@ typedef struct drm_i915_private {
 		struct list_head flushing_list;
 
 		/**
+		 * List of objects currently pending a GPU write.
+		 *
+		 * All elements on this list will belong to either the
+		 * active_list or flushing_list, last_rendering_seqno can
+		 * be used to differentiate between the two elements.
+		 */
+		struct list_head gpu_write_list;
+
+		/**
 		 * LRU list of objects which are not in the ringbuffer and
 		 * are ready to unbind, but are still in the GTT.
 		 *
@@ -599,6 +608,8 @@ struct drm_i915_gem_object {
 
 	/** This object's place on the active/flushing/inactive lists */
 	struct list_head list;
+	/** This object's place on GPU write list */
+	struct list_head gpu_write_list;
 
 	/** This object's place on the fenced object LRU */
 	struct list_head fence_list;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index ddea92c..83ef4b8 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1568,6 +1568,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
 	else
 		list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
 
+	BUG_ON(!list_empty(&obj_priv->gpu_write_list));
+
 	obj_priv->last_rendering_seqno = 0;
 	if (obj_priv->active) {
 		obj_priv->active = 0;
@@ -1631,21 +1633,21 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
 		INIT_LIST_HEAD(&request->client_list);
 	}
 
-	/* Associate any objects on the flushing list matching the write
+	/* Associate any objects on the gpu_write_list matching the write
 	 * domain we're flushing with our flush.
 	 */
-	if (flush_domains != 0) {
+	if (flush_domains & I915_GEM_GPU_DOMAINS) {
 		struct drm_i915_gem_object *obj_priv, *next;
 
 		list_for_each_entry_safe(obj_priv, next,
-					 &dev_priv->mm.flushing_list, list) {
+					 &dev_priv->mm.gpu_write_list,
+					 gpu_write_list) {
 			struct drm_gem_object *obj = obj_priv->obj;
 
-			if ((obj->write_domain & flush_domains) ==
-			    obj->write_domain) {
+			if (obj->write_domain & flush_domains) {
 				uint32_t old_write_domain = obj->write_domain;
-
 				obj->write_domain = 0;
+				list_del_init(&obj_priv->gpu_write_list);
 				i915_gem_object_move_to_active(obj, seqno);
 
 				trace_i915_gem_object_change_domain(obj,
@@ -1653,7 +1655,6 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
 								    old_write_domain);
 			}
 		}
-
 	}
 
 	if (!dev_priv->mm.suspended) {
@@ -2711,22 +2712,13 @@ static void
 i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
 {
 	struct drm_device *dev = obj->dev;
-	uint32_t seqno;
-	uint32_t old_write_domain;
 
 	if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
 		return;
 
 	/* Queue the GPU write cache flushing we need. */
-	old_write_domain = obj->write_domain;
 	i915_gem_flush(dev, 0, obj->write_domain);
-	seqno = i915_add_request(dev, NULL, obj->write_domain);
-	obj->write_domain = 0;
-	i915_gem_object_move_to_active(obj, seqno);
-
-	trace_i915_gem_object_change_domain(obj,
-					    obj->read_domains,
-					    old_write_domain);
+	(void) i915_add_request(dev, NULL, obj->write_domain);
 }
 
 /** Flushes the GTT write domain for the object if it's dirty. */
@@ -3867,16 +3859,23 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 		i915_gem_flush(dev,
 			       dev->invalidate_domains,
 			       dev->flush_domains);
-		if (dev->flush_domains)
+		if (dev->flush_domains & I915_GEM_GPU_DOMAINS)
 			(void)i915_add_request(dev, file_priv,
 					       dev->flush_domains);
 	}
 
 	for (i = 0; i < args->buffer_count; i++) {
 		struct drm_gem_object *obj = object_list[i];
+		struct drm_i915_gem_object *obj_priv = obj->driver_private;
 		uint32_t old_write_domain = obj->write_domain;
 
 		obj->write_domain = obj->pending_write_domain;
+		if (obj->write_domain)
+			list_move_tail(&obj_priv->gpu_write_list,
+				       &dev_priv->mm.gpu_write_list);
+		else
+			list_del_init(&obj_priv->gpu_write_list);
+
 		trace_i915_gem_object_change_domain(obj,
 						    obj->read_domains,
 						    old_write_domain);
@@ -4387,6 +4386,7 @@ int i915_gem_init_object(struct drm_gem_object *obj)
 	obj_priv->obj = obj;
 	obj_priv->fence_reg = I915_FENCE_REG_NONE;
 	INIT_LIST_HEAD(&obj_priv->list);
+	INIT_LIST_HEAD(&obj_priv->gpu_write_list);
 	INIT_LIST_HEAD(&obj_priv->fence_list);
 	obj_priv->madv = I915_MADV_WILLNEED;
 
@@ -4782,6 +4782,7 @@ i915_gem_load(struct drm_device *dev)
 	spin_lock_init(&dev_priv->mm.active_list_lock);
 	INIT_LIST_HEAD(&dev_priv->mm.active_list);
 	INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
+	INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
 	INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
 	INIT_LIST_HEAD(&dev_priv->mm.request_list);
 	INIT_LIST_HEAD(&dev_priv->mm.fence_list);
-- 
1.6.6.1




More information about the Intel-gfx mailing list