[kernel] r16523 - in dists/sid/linux-2.6/debian: . patches/bugfix/all patches/series

Maximilian Attems maks at alioth.debian.org
Tue Nov 2 10:08:21 UTC 2010


Author: maks
Date: Tue Nov  2 10:08:14 2010
New Revision: 16523

Log:
drm/nouveau: fix race condition when under memory pressure

seen in F13, not a direct trivial backport, will build and ask
nouveau testers to run this. corresponding rhbz 602956 is private.

Added:
   dists/sid/linux-2.6/debian/patches/bugfix/all/drm-nouveau-fix-race-condition-when-under-memory-pre.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/patches/series/28

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	Tue Nov  2 09:29:59 2010	(r16522)
+++ dists/sid/linux-2.6/debian/changelog	Tue Nov  2 10:08:14 2010	(r16523)
@@ -5,6 +5,7 @@
   * images: Nuke modules.devname on removal. (closes: #590607)
   * Newer Standards-Version 3.9.1 without changes.
   * drm/ttm: Clear the ghost cpu_writers flag on ttm_buffer_object_transfer.
+  * drm/nouveau: fix race condition when under memory pressure.
 
  -- maximilian attems <maks at debian.org>  Sat, 30 Oct 2010 14:14:37 +0200
 

Added: dists/sid/linux-2.6/debian/patches/bugfix/all/drm-nouveau-fix-race-condition-when-under-memory-pre.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/drm-nouveau-fix-race-condition-when-under-memory-pre.patch	Tue Nov  2 10:08:14 2010	(r16523)
@@ -0,0 +1,133 @@
+From 415e6186f17136075f7cc825ba3835d005773637 Mon Sep 17 00:00:00 2001
+From: Ben Skeggs <bskeggs at redhat.com>
+Date: Fri, 23 Jul 2010 09:06:52 +1000
+Subject: [PATCH] drm/nouveau: fix race condition when under memory pressure
+
+When VRAM is running out it's possible that the client's push buffers get
+evicted to main memory.  When they're validated back in, the GPU may
+be used for the copy back to VRAM, but the existing synchronisation code
+only deals with inter-channel sync, not sync between PFIFO and PGRAPH on
+the same channel.  This leads to PFIFO fetching from command buffers that
+haven't quite been copied by PGRAPH yet.
+
+This patch marks push buffers as so, and forces any GPU-assisted buffer
+moves to be done on a different channel, which triggers the correct
+synchronisation to happen before we submit them.
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+[ Backported to our drm tree - maks ]
+---
+ drivers/gpu/drm/nouveau/nouveau_bo.c  |   15 +++++++++++++
+ drivers/gpu/drm/nouveau/nouveau_drv.h |    1 +
+ drivers/gpu/drm/nouveau/nouveau_gem.c |   36 +++++++++++++++++++++++---------
+ 3 files changed, 42 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
+index 84f8518..f6f4477 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
++++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
+@@ -36,6 +36,21 @@
+ #include <linux/log2.h>
+ #include <linux/slab.h>
+ 
++int
++nouveau_bo_sync_gpu(struct nouveau_bo *nvbo, struct nouveau_channel *chan)
++{
++	struct nouveau_fence *prev_fence = nvbo->bo.sync_obj;
++	int ret;
++
++	if (!prev_fence || nouveau_fence_channel(prev_fence) == chan)
++		return 0;
++
++	spin_lock(&nvbo->bo.lock);
++	ret = ttm_bo_wait(&nvbo->bo, false, false, false);
++	spin_unlock(&nvbo->bo.lock);
++	return ret;
++}
++
+ static void
+ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
+ {
+diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
+index e424bf7..1e093a0 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
+@@ -1165,6 +1165,7 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index);
+ extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
+ extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
+ extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val);
++extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *);
+ 
+ /* nouveau_fence.c */
+ struct nouveau_fence;
+diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
+index 547f2c2..a915dcd 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
++++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
+@@ -361,14 +361,11 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
+ 
+ 	list_for_each_entry(nvbo, list, entry) {
+ 		struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
+-		struct nouveau_fence *prev_fence = nvbo->bo.sync_obj;
+ 
+-		if (prev_fence && nouveau_fence_channel(prev_fence) != chan) {
+-			spin_lock(&nvbo->bo.lock);
+-			ret = ttm_bo_wait(&nvbo->bo, false, false, false);
+-			spin_unlock(&nvbo->bo.lock);
+-			if (unlikely(ret))
+-				return ret;
++		ret = nouveau_bo_sync_gpu(nvbo, chan);
++		if (unlikely(ret)) {
++			NV_ERROR(dev, "fail pre-validate sync\n");
++			return ret;
+ 		}
+ 
+ 		ret = nouveau_gem_set_domain(nvbo->gem, b->read_domains,
+@@ -381,7 +376,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
+ 		if (unlikely(ret))
+ 			return ret;
+ 
+-		nvbo->channel = chan;
++		nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan;
+ 		ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement,
+ 				      false, false);
+ 		nvbo->channel = NULL;
+@@ -390,6 +385,12 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
+ 		if (unlikely(ret))
+ 			return ret;
+ 
++		ret = nouveau_bo_sync_gpu(nvbo, chan);
++		if (unlikely(ret)) {
++			NV_ERROR(dev, "fail post-validate sync\n");
++			return ret;
++		}
++
+ 		if (nvbo->bo.offset == b->presumed_offset &&
+ 		    ((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
+ 		      b->presumed_domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
+@@ -615,6 +616,21 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
+ 
+ 	mutex_lock(&dev->struct_mutex);
+ 
++	/* Mark push buffers as being used on PFIFO, the validation code
++	 * will then make sure that if the pushbuf bo moves, that they
++	 * happen on the kernel channel, which will in turn cause a sync
++	 * to happen before we try and submit the push buffer.
++	 */
++	for (i = 0; i < req->nr_push; i++) {
++		if (push[i].bo_index >= req->nr_buffers) {
++			NV_ERROR(dev, "push %d buffer not in list\n", i);
++			ret = -EINVAL;
++			goto out;
++		}
++
++		bo[push[i].bo_index].read_domains |= (1 << 31);
++	}
++
+ 	/* Validate buffer list */
+ 	ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers,
+ 					   req->nr_buffers, &op, &do_reloc);
+-- 
+1.7.2.3
+

Modified: dists/sid/linux-2.6/debian/patches/series/28
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/28	Tue Nov  2 09:29:59 2010	(r16522)
+++ dists/sid/linux-2.6/debian/patches/series/28	Tue Nov  2 10:08:14 2010	(r16523)
@@ -1,3 +1,4 @@
 + bugfix/all/ipc_initialize_structure_memory_to_zero.patch
 + bugfix/all/drm-i915-set-DIDL-using-the-ACPI-video-output-device.patch
 + bugfix/all/drm-ttm-Clear-the-ghost-cpu_writers-flag-on-ttm_buff.patch
++ bugfix/all/drm-nouveau-fix-race-condition-when-under-memory-pre.patch



More information about the Kernel-svn-changes mailing list