From 695599f18d907bb277805581bbe208b0e083e7d9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 19:03:35 +1000 Subject: nouveau: Nuke DMA_OBJECT_INIT ioctl (bumps interface to 0.0.7) For various reasons, this ioctl was a bad idea. At channel creation we now automatically create DMA objects covering available VRAM and GART memory, where the client used to do this themselves. However, there is still a need to be able to create DMA objects pointing at specific areas of memory (ie. notifiers). Each channel is now allocated a small amount of memory from which a client can suballocate things (such as notifiers), and have a DMA object created which covers the suballocated area. The NOTIFIER_ALLOC ioctl exposes this functionality. --- shared-core/nouveau_notifier.c | 154 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 shared-core/nouveau_notifier.c (limited to 'shared-core/nouveau_notifier.c') diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c new file mode 100644 index 00000000..ab6f8c2d --- /dev/null +++ b/shared-core/nouveau_notifier.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +int +nouveau_notifier_init_channel(drm_device_t *dev, int channel, DRMFILE filp) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + int flags, ret; + + /*TODO: PCI notifier blocks */ + if (dev_priv->agp_heap) + flags = NOUVEAU_MEM_AGP | NOUVEAU_MEM_FB_ACCEPTABLE; + else + flags = NOUVEAU_MEM_FB; + + chan->notifier_block = nouveau_mem_alloc(dev, 0, PAGE_SIZE, flags,filp); + if (!chan->notifier_block) + return DRM_ERR(ENOMEM); + + ret = nouveau_mem_init_heap(&chan->notifier_heap, + 0, chan->notifier_block->size); + if (ret) + return ret; + + return 0; +} + +void +nouveau_notifier_takedown_channel(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + + if (chan->notifier_block) { + nouveau_mem_free(dev, chan->notifier_block); + chan->notifier_block = NULL; + } + + /*XXX: heap destroy */ +} + +int +nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, + int count, uint32_t *b_offset) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_object *obj; + struct mem_block *mem; + uint32_t offset; + int target; + + if (!chan->notifier_heap) { + DRM_ERROR("Channel %d doesn't have a notifier heap!\n", + channel); + return DRM_ERR(EINVAL); + } + + mem = nouveau_mem_alloc_block(chan->notifier_heap, 32, 0, chan->filp); + if (!mem) { + DRM_ERROR("Channel %d notifier block full\n", channel); + return DRM_ERR(ENOMEM); + } + mem->flags = NOUVEAU_MEM_NOTIFIER; + + offset = chan->notifier_block->start + mem->start; + if (chan->notifier_block->flags & NOUVEAU_MEM_FB) { + offset -= drm_get_resource_start(dev, 1); + target = NV_DMA_TARGET_VIDMEM; + } else if (chan->notifier_block->flags & NOUVEAU_MEM_AGP) { + offset -= dev_priv->agp_phys; + target = NV_DMA_TARGET_AGP; + } else { + DRM_ERROR("Bad DMA target, flags 0x%08x!\n", + chan->notifier_block->flags); + return DRM_ERR(EINVAL); + } + + obj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, + offset, mem->size, NV_DMA_ACCESS_RW, + target); + if (!obj) { + nouveau_mem_free_block(mem); + DRM_ERROR("Error creating notifier ctxdma\n"); + return DRM_ERR(ENOMEM); + } + + obj->handle = handle; + if (nouveau_ht_object_insert(dev, channel, handle, obj)) { + nouveau_object_free(dev, obj); + nouveau_mem_free_block(mem); + DRM_ERROR("Error inserting notifier ctxdma into RAMHT\n"); + return DRM_ERR(ENOMEM); + } + + *b_offset = mem->start; + return 0; +} + +int +nouveau_ioctl_notifier_alloc(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_nouveau_notifier_alloc_t na; + int ret; + + DRM_COPY_FROM_USER_IOCTL(na, (drm_nouveau_notifier_alloc_t __user*)data, + sizeof(na)); + + if (!nouveau_fifo_owner(dev, filp, na.channel)) { + DRM_ERROR("pid %d doesn't own channel %d\n", + DRM_CURRENTPID, na.channel); + return DRM_ERR(EPERM); + } + + ret = nouveau_notifier_alloc(dev, na.channel, na.handle, + na.count, &na.offset); + if (ret) + return ret; + + DRM_COPY_TO_USER_IOCTL((drm_nouveau_notifier_alloc_t __user*)data, + na, sizeof(na)); + return 0; +} + -- cgit v1.2.3 From 68ecf61647e9ec16d59cc8f50550d11478eb3118 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 25 Jun 2007 15:42:55 +1000 Subject: nouveau: never touch PRAMIN with NV_WRITE, cleanup RAMHT code a bit --- shared-core/nouveau_notifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-core/nouveau_notifier.c') diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index ab6f8c2d..0cfe733e 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -115,7 +115,7 @@ nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, } obj->handle = handle; - if (nouveau_ht_object_insert(dev, channel, handle, obj)) { + if (nouveau_ramht_insert(dev, channel, handle, obj)) { nouveau_object_free(dev, obj); nouveau_mem_free_block(mem); DRM_ERROR("Error inserting notifier ctxdma into RAMHT\n"); -- cgit v1.2.3 From 163f8526123ffa38783fc911b5f7a19debce7f73 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 2 Jul 2007 19:31:18 +1000 Subject: nouveau: rewrite gpu object code Allows multiple references to a single object, needed to support PCI(E)GART scatter-gather DMA objects which would quickly fill PRAMIN if each channel had its own. Handle per-channel private instmem areas. This is needed to support NV50, but might be something we want to do on earlier chipsets at some point? Everything that touches PRAMIN is a GPU object. --- shared-core/nouveau_notifier.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'shared-core/nouveau_notifier.c') diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 0cfe733e..4d5e26ab 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -74,10 +74,10 @@ nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, { drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - struct nouveau_object *obj; + nouveau_gpuobj_t *nobj = NULL; struct mem_block *mem; uint32_t offset; - int target; + int target, ret; if (!chan->notifier_heap) { DRM_ERROR("Channel %d doesn't have a notifier heap!\n", @@ -105,21 +105,19 @@ nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, return DRM_ERR(EINVAL); } - obj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, - offset, mem->size, NV_DMA_ACCESS_RW, - target); - if (!obj) { + if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + offset, mem->size, + NV_DMA_ACCESS_RW, target, &nobj))) { nouveau_mem_free_block(mem); - DRM_ERROR("Error creating notifier ctxdma\n"); - return DRM_ERR(ENOMEM); + DRM_ERROR("Error creating notifier ctxdma: %d\n", ret); + return ret; } - obj->handle = handle; - if (nouveau_ramht_insert(dev, channel, handle, obj)) { - nouveau_object_free(dev, obj); + if ((ret = nouveau_gpuobj_ref_add(dev, channel, handle, nobj, NULL))) { + nouveau_gpuobj_del(dev, &nobj); nouveau_mem_free_block(mem); - DRM_ERROR("Error inserting notifier ctxdma into RAMHT\n"); - return DRM_ERR(ENOMEM); + DRM_ERROR("Error referencing notifier ctxdma: %d\n", ret); + return ret; } *b_offset = mem->start; -- cgit v1.2.3 From c806bba4665bb369168ee0b453fa28e2e0bf2a5d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 5 Jul 2007 00:12:33 +1000 Subject: nouveau/nv50: Initial channel/object support Should be OK on G84 for a single channel, multiple channels *almost* work. Untested on G80. --- shared-core/nouveau_notifier.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'shared-core/nouveau_notifier.c') diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 4d5e26ab..9e792e57 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -33,7 +33,7 @@ int nouveau_notifier_init_channel(drm_device_t *dev, int channel, DRMFILE filp) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; int flags, ret; /*TODO: PCI notifier blocks */ @@ -58,7 +58,7 @@ void nouveau_notifier_takedown_channel(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; if (chan->notifier_block) { nouveau_mem_free(dev, chan->notifier_block); @@ -73,7 +73,7 @@ nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, int count, uint32_t *b_offset) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; nouveau_gpuobj_t *nobj = NULL; struct mem_block *mem; uint32_t offset; -- cgit v1.2.3 From 023f7d9c0064f912415c92a85c3a9d722191909f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 9 Jul 2007 23:58:00 +1000 Subject: nouveau: Allocate mappable VRAM for notifiers.. --- shared-core/nouveau_notifier.c | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-core/nouveau_notifier.c') diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 9e792e57..30216293 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -41,6 +41,7 @@ nouveau_notifier_init_channel(drm_device_t *dev, int channel, DRMFILE filp) flags = NOUVEAU_MEM_AGP | NOUVEAU_MEM_FB_ACCEPTABLE; else flags = NOUVEAU_MEM_FB; + flags |= NOUVEAU_MEM_MAPPED; chan->notifier_block = nouveau_mem_alloc(dev, 0, PAGE_SIZE, flags,filp); if (!chan->notifier_block) -- cgit v1.2.3