From 05633ca3708f48cfbbb77518da4e791d7e1613c2 Mon Sep 17 00:00:00 2001
From: Ben Skeggs <skeggsb@gmail.com>
Date: Wed, 8 Aug 2007 16:37:55 +1000
Subject: nouveau: Always allocate drm's push buffer in VRAM

Fixes #11868
---
 shared-core/nouveau_dma.c  | 11 ++++++-
 shared-core/nouveau_drv.h  |  1 +
 shared-core/nouveau_fifo.c | 78 +++++++++++++++++++++++++---------------------
 3 files changed, 53 insertions(+), 37 deletions(-)

(limited to 'shared-core')

diff --git a/shared-core/nouveau_dma.c b/shared-core/nouveau_dma.c
index ce5b6299..ab502e6a 100644
--- a/shared-core/nouveau_dma.c
+++ b/shared-core/nouveau_dma.c
@@ -37,13 +37,22 @@ nouveau_dma_channel_init(struct drm_device *dev)
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_drm_channel *dchan = &dev_priv->channel;
 	struct nouveau_gpuobj *gpuobj = NULL;
+	struct mem_block *pushbuf;
 	int grclass, ret, i;
 
 	DRM_DEBUG("\n");
 
+	pushbuf = nouveau_mem_alloc(dev, 0, 0x8000,
+				    NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED,
+				    (struct drm_file *)-2);
+	if (!pushbuf) {
+		DRM_ERROR("Failed to allocate DMA push buffer\n");
+		return -ENOMEM;
+	}
+
 	/* Allocate channel */
 	ret = nouveau_fifo_alloc(dev, &dchan->chan, (struct drm_file *)-2,
-				 NvDmaFB, NvDmaTT);
+				 pushbuf, NvDmaFB, NvDmaTT);
 	if (ret) {
 		DRM_ERROR("Error allocating GPU channel: %d\n", ret);
 		return ret;
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index 10f9149e..572df46e 100644
--- a/shared-core/nouveau_drv.h
+++ b/shared-core/nouveau_drv.h
@@ -365,6 +365,7 @@ extern int  nouveau_fifo_owner(struct drm_device *, struct drm_file *,
 extern int  nouveau_fifo_alloc(struct drm_device *dev,
 			       struct nouveau_channel **chan,
 			       struct drm_file *file_priv,
+			       struct mem_block *pushbuf,
 			       uint32_t fb_ctxdma, uint32_t tt_ctxdma);
 extern void nouveau_fifo_free(struct nouveau_channel *);
 
diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c
index f9677514..22bced14 100644
--- a/shared-core/nouveau_fifo.c
+++ b/shared-core/nouveau_fifo.c
@@ -190,46 +190,30 @@ int nouveau_fifo_init(struct drm_device *dev)
 }
 
 static int
-nouveau_fifo_cmdbuf_alloc(struct nouveau_channel *chan)
+nouveau_fifo_pushbuf_ctxdma_init(struct nouveau_channel *chan)
 {
 	struct drm_device *dev = chan->dev;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_config *config = &dev_priv->config;
-	struct mem_block *cb;
-	int cb_min_size = max(NV03_FIFO_SIZE,PAGE_SIZE);
+	struct mem_block *pb = chan->pushbuf_mem;
 	struct nouveau_gpuobj *pushbuf = NULL;
 	int ret;
 
-	/* Defaults for unconfigured values */
-	if (!config->cmdbuf.location)
-		config->cmdbuf.location = NOUVEAU_MEM_FB;
-	if (!config->cmdbuf.size || config->cmdbuf.size < cb_min_size)
-		config->cmdbuf.size = cb_min_size;
-
-	cb = nouveau_mem_alloc(dev, 0, config->cmdbuf.size,
-			config->cmdbuf.location | NOUVEAU_MEM_MAPPED,
-			(struct drm_file *)-2);
-	if (!cb) {
-		DRM_ERROR("Couldn't allocate DMA command buffer.\n");
-		return -ENOMEM;
-	}
-
-	if (cb->flags & NOUVEAU_MEM_AGP) {
-		ret = nouveau_gpuobj_gart_dma_new(chan, cb->start, cb->size,
+	if (pb->flags & NOUVEAU_MEM_AGP) {
+		ret = nouveau_gpuobj_gart_dma_new(chan, pb->start, pb->size,
 						  NV_DMA_ACCESS_RO,
 						  &pushbuf,
 						  &chan->pushbuf_base);
 	} else
-	if (cb->flags & NOUVEAU_MEM_PCI) {
+	if (pb->flags & NOUVEAU_MEM_PCI) {
 		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-					     cb->start, cb->size,
+					     pb->start, pb->size,
 					     NV_DMA_ACCESS_RO,
 					     NV_DMA_TARGET_PCI_NONLINEAR,
 					     &pushbuf);
 		chan->pushbuf_base = 0;
 	} else if (dev_priv->card_type != NV_04) {
 		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-					     cb->start, cb->size,
+					     pb->start, pb->size,
 					     NV_DMA_ACCESS_RO,
 					     NV_DMA_TARGET_VIDMEM, &pushbuf);
 		chan->pushbuf_base = 0;
@@ -239,19 +223,13 @@ nouveau_fifo_cmdbuf_alloc(struct nouveau_channel *chan)
 		 * VRAM.
 		 */
 		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-					     cb->start +
+					     pb->start +
 					       drm_get_resource_start(dev, 1),
-					     cb->size, NV_DMA_ACCESS_RO,
+					     pb->size, NV_DMA_ACCESS_RO,
 					     NV_DMA_TARGET_PCI, &pushbuf);
 		chan->pushbuf_base = 0;
 	}
 
-	if (ret) {
-		nouveau_mem_free(dev, cb);
-		DRM_ERROR("Error creating push buffer ctxdma: %d\n", ret);
-		return ret;
-	}
-
 	if ((ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf,
 					  &chan->pushbuf))) {
 		DRM_ERROR("Error referencing push buffer ctxdma: %d\n", ret);
@@ -260,14 +238,36 @@ nouveau_fifo_cmdbuf_alloc(struct nouveau_channel *chan)
 		return ret;
 	}
 
-	chan->pushbuf_mem = cb;
 	return 0;
 }
 
+static struct mem_block *
+nouveau_fifo_user_pushbuf_alloc(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_config *config = &dev_priv->config;
+	struct mem_block *pb;
+	int pb_min_size = max(NV03_FIFO_SIZE,PAGE_SIZE);
+
+	/* Defaults for unconfigured values */
+	if (!config->cmdbuf.location)
+		config->cmdbuf.location = NOUVEAU_MEM_FB;
+	if (!config->cmdbuf.size || config->cmdbuf.size < pb_min_size)
+		config->cmdbuf.size = pb_min_size;
+
+	pb = nouveau_mem_alloc(dev, 0, config->cmdbuf.size,
+			       config->cmdbuf.location | NOUVEAU_MEM_MAPPED,
+			       (struct drm_file *)-2);
+	if (!pb)
+		DRM_ERROR("Couldn't allocate DMA push buffer.\n");
+
+	return pb;
+}
+
 /* allocates and initializes a fifo for user space consumption */
 int
 nouveau_fifo_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
-		   struct drm_file *file_priv,
+		   struct drm_file *file_priv, struct mem_block *pushbuf,
 		   uint32_t vram_handle, uint32_t tt_handle)
 {
 	int ret;
@@ -303,6 +303,7 @@ nouveau_fifo_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
 	chan->dev = dev;
 	chan->id = channel;
 	chan->file_priv = file_priv;
+	chan->pushbuf_mem = pushbuf;
 
 	DRM_INFO("Allocating FIFO number %d\n", channel);
 
@@ -320,8 +321,8 @@ nouveau_fifo_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
 		return ret;
 	}
 
-	/* allocate a command buffer, and create a dma object for the gpu */
-	ret = nouveau_fifo_cmdbuf_alloc(chan);
+	/* Create a dma object for the push buffer */
+	ret = nouveau_fifo_pushbuf_ctxdma_init(chan);
 	if (ret) {
 		nouveau_fifo_free(chan);
 		return ret;
@@ -467,6 +468,7 @@ static int nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
 	struct drm_nouveau_channel_alloc *init = data;
 	struct drm_map_list *entry;
 	struct nouveau_channel *chan;
+	struct mem_block *pushbuf;
 	int res;
 
 	NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
@@ -474,7 +476,11 @@ static int nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
 	if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
 		return -EINVAL;
 
-	res = nouveau_fifo_alloc(dev, &chan, file_priv,
+	pushbuf = nouveau_fifo_user_pushbuf_alloc(dev);
+	if (!pushbuf)
+		return -ENOMEM;
+
+	res = nouveau_fifo_alloc(dev, &chan, file_priv, pushbuf,
 				 init->fb_ctxdma_handle,
 				 init->tt_ctxdma_handle);
 	if (res)
-- 
cgit v1.2.3