summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <skeggsb@gmail.com>2007-06-24 19:03:35 +1000
committerBen Skeggs <skeggsb@gmail.com>2007-06-28 03:26:43 +1000
commit695599f18d907bb277805581bbe208b0e083e7d9 (patch)
tree49180607fa582f77157f5f83ab79dc2ceb9f53fc
parent4f2dd78ff3b6efeee97b72cca6bbfaef485a08d9 (diff)
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.
-rw-r--r--linux-core/Makefile.kernel2
l---------linux-core/nouveau_notifier.c1
-rw-r--r--shared-core/nouveau_drm.h28
-rw-r--r--shared-core/nouveau_drv.h28
-rw-r--r--shared-core/nouveau_fifo.c45
-rw-r--r--shared-core/nouveau_mem.c51
-rw-r--r--shared-core/nouveau_notifier.c154
-rw-r--r--shared-core/nouveau_object.c143
-rw-r--r--shared-core/nouveau_state.c3
9 files changed, 315 insertions, 140 deletions
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel
index 9427a04b..6ab17a49 100644
--- a/linux-core/Makefile.kernel
+++ b/linux-core/Makefile.kernel
@@ -21,7 +21,7 @@ i810-objs := i810_drv.o i810_dma.o
i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \
i915_buffer.o
nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
- nouveau_object.o nouveau_irq.o \
+ nouveau_object.o nouveau_irq.o nouveau_notifier.o \
nv04_timer.o \
nv04_mc.o nv40_mc.o \
nv04_fb.o nv10_fb.o nv40_fb.o \
diff --git a/linux-core/nouveau_notifier.c b/linux-core/nouveau_notifier.c
new file mode 120000
index 00000000..285469c5
--- /dev/null
+++ b/linux-core/nouveau_notifier.c
@@ -0,0 +1 @@
+../shared-core/nouveau_notifier.c \ No newline at end of file
diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h
index 1e7322e0..0758991a 100644
--- a/shared-core/nouveau_drm.h
+++ b/shared-core/nouveau_drm.h
@@ -25,9 +25,12 @@
#ifndef __NOUVEAU_DRM_H__
#define __NOUVEAU_DRM_H__
-#define NOUVEAU_DRM_HEADER_PATCHLEVEL 6
+#define NOUVEAU_DRM_HEADER_PATCHLEVEL 7
typedef struct drm_nouveau_fifo_alloc {
+ uint32_t fb_ctxdma_handle;
+ uint32_t tt_ctxdma_handle;
+
int channel;
uint32_t put_base;
/* FIFO control regs */
@@ -36,29 +39,30 @@ typedef struct drm_nouveau_fifo_alloc {
/* DMA command buffer */
drm_handle_t cmdbuf;
int cmdbuf_size;
+ /* Notifier memory */
+ drm_handle_t notifier;
+ int notifier_size;
}
drm_nouveau_fifo_alloc_t;
-typedef struct drm_nouveau_object_init {
+typedef struct drm_nouveau_grobj_alloc {
int channel;
uint32_t handle;
int class;
}
-drm_nouveau_object_init_t;
+drm_nouveau_grobj_alloc_t;
#define NOUVEAU_MEM_ACCESS_RO 1
#define NOUVEAU_MEM_ACCESS_WO 2
#define NOUVEAU_MEM_ACCESS_RW 3
-typedef struct drm_nouveau_dma_object_init {
+typedef struct drm_nouveau_notifier_alloc {
int channel;
uint32_t handle;
- int class;
- int access;
- int target;
+ int count;
+
uint32_t offset;
- int size;
}
-drm_nouveau_dma_object_init_t;
+drm_nouveau_notifier_alloc_t;
#define NOUVEAU_MEM_FB 0x00000001
#define NOUVEAU_MEM_AGP 0x00000002
@@ -68,7 +72,7 @@ drm_nouveau_dma_object_init_t;
#define NOUVEAU_MEM_USER_BACKED 0x00000020
#define NOUVEAU_MEM_MAPPED 0x00000040
#define NOUVEAU_MEM_INSTANCE 0x00000080 /* internal */
-
+#define NOUVEAU_MEM_NOTIFIER 0x00000100 /* internal */
typedef struct drm_nouveau_mem_alloc {
int flags;
int alignment;
@@ -141,8 +145,8 @@ typedef struct drm_nouveau_sarea {
drm_nouveau_sarea_t;
#define DRM_NOUVEAU_FIFO_ALLOC 0x00
-#define DRM_NOUVEAU_OBJECT_INIT 0x01
-#define DRM_NOUVEAU_DMA_OBJECT_INIT 0x02
+#define DRM_NOUVEAU_GROBJ_ALLOC 0x01
+#define DRM_NOUVEAU_NOTIFIER_ALLOC 0x02
#define DRM_NOUVEAU_MEM_ALLOC 0x03
#define DRM_NOUVEAU_MEM_FREE 0x04
#define DRM_NOUVEAU_GETPARAM 0x05
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index b3122d8a..7a1ca3d5 100644
--- a/shared-core/nouveau_drv.h
+++ b/shared-core/nouveau_drv.h
@@ -34,7 +34,7 @@
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 0
-#define DRIVER_PATCHLEVEL 6
+#define DRIVER_PATCHLEVEL 7
#define NOUVEAU_FAMILY 0x0000FFFF
#define NOUVEAU_FLAGS 0xFFFF0000
@@ -84,6 +84,10 @@ struct nouveau_fifo
struct mem_block *cmdbuf_mem;
struct nouveau_object *cmdbuf_obj;
uint32_t pushbuf_base;
+ /* notifier memory */
+ struct mem_block *notifier_block;
+ struct mem_block *notifier_heap;
+ drm_local_map_t *notifier_map;
/* PGRAPH context, for cards that keep it in RAMIN */
struct mem_block *ramin_grctx;
/* objects belonging to this fifo */
@@ -197,6 +201,12 @@ extern void nouveau_wait_for_idle(struct drm_device *dev);
extern int nouveau_ioctl_card_init(DRM_IOCTL_ARGS);
/* nouveau_mem.c */
+extern int nouveau_mem_init_heap(struct mem_block **,
+ uint64_t start, uint64_t size);
+extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *,
+ uint64_t size, int align2,
+ DRMFILE);
+extern void nouveau_mem_free_block(struct mem_block *);
extern uint64_t nouveau_mem_fb_amount(struct drm_device *dev);
extern void nouveau_mem_release(DRMFILE filp, struct mem_block *heap);
extern int nouveau_ioctl_mem_alloc(DRM_IOCTL_ARGS);
@@ -216,6 +226,13 @@ extern void nouveau_instmem_w32(drm_nouveau_private_t *dev_priv,
struct mem_block *mem, int index,
uint32_t val);
+/* nouveau_notifier.c */
+extern int nouveau_notifier_init_channel(drm_device_t *, int channel, DRMFILE);
+extern void nouveau_notifier_takedown_channel(drm_device_t *, int channel);
+extern int nouveau_notifier_alloc(drm_device_t *, int channel,
+ uint32_t handle, int cout, uint32_t *offset);
+extern int nouveau_ioctl_notifier_alloc(DRM_IOCTL_ARGS);
+
/* nouveau_fifo.c */
extern int nouveau_fifo_init(drm_device_t *dev);
extern int nouveau_fifo_number(drm_device_t *dev);
@@ -225,7 +242,13 @@ extern int nouveau_fifo_owner(drm_device_t *dev, DRMFILE filp, int channel);
extern void nouveau_fifo_free(drm_device_t *dev, int channel);
/* nouveau_object.c */
+extern int nouveau_object_init_channel(drm_device_t *, int channel,
+ uint32_t vram_handle,
+ uint32_t tt_handle);
+extern void nouveau_object_takedown_channel(drm_device_t *dev, int channel);
extern void nouveau_object_cleanup(drm_device_t *dev, int channel);
+extern int nouveau_ht_object_insert(drm_device_t *, int channel,
+ uint32_t handle, struct nouveau_object *);
extern struct nouveau_object *
nouveau_object_gr_create(drm_device_t *dev, int channel, int class);
extern struct nouveau_object *
@@ -233,8 +256,7 @@ nouveau_object_dma_create(drm_device_t *dev, int channel, int class,
uint32_t offset, uint32_t size,
int access, int target);
extern void nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj);
-extern int nouveau_ioctl_object_init(DRM_IOCTL_ARGS);
-extern int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS);
+extern int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS);
extern uint32_t nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem);
/* nouveau_irq.c */
diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c
index 1a06f913..f179af63 100644
--- a/shared-core/nouveau_fifo.c
+++ b/shared-core/nouveau_fifo.c
@@ -241,7 +241,8 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel)
}
/* allocates and initializes a fifo for user space consumption */
-static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
+int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp,
+ uint32_t vram_handle, uint32_t tt_handle)
{
int ret;
drm_nouveau_private_t *dev_priv = dev->dev_private;
@@ -282,6 +283,20 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
return ret;
}
+ /* Setup channel's default objects */
+ ret = nouveau_object_init_channel(dev, channel, vram_handle, tt_handle);
+ if (ret) {
+ nouveau_fifo_free(dev, channel);
+ return ret;
+ }
+
+ /* Allocate space for per-channel fixed notifier memory */
+ ret = nouveau_notifier_init_channel(dev, channel, filp);
+ if (ret) {
+ nouveau_fifo_free(dev, channel);
+ return ret;
+ }
+
nouveau_wait_for_idle(dev);
/* disable the fifo caches */
@@ -370,6 +385,8 @@ void nouveau_fifo_free(drm_device_t* dev, int channel)
if (chan->cmdbuf_mem)
nouveau_mem_free(dev, chan->cmdbuf_mem);
+ nouveau_notifier_takedown_channel(dev, channel);
+
/* Destroy objects belonging to the channel */
nouveau_object_cleanup(dev, channel);
@@ -408,30 +425,42 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan;
drm_nouveau_fifo_alloc_t init;
int res;
DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_fifo_alloc_t __user *) data,
sizeof(init));
- res = nouveau_fifo_alloc(dev, &init.channel, filp);
+ res = nouveau_fifo_alloc(dev, &init.channel, filp,
+ init.fb_ctxdma_handle,
+ init.tt_ctxdma_handle);
if (res)
return res;
+ chan = &dev_priv->fifos[init.channel];
- init.put_base = dev_priv->fifos[init.channel].pushbuf_base;
+ init.put_base = chan->pushbuf_base;
/* make the fifo available to user space */
/* first, the fifo control regs */
init.ctrl = dev_priv->mmio->offset + NV03_FIFO_REGS(init.channel);
init.ctrl_size = NV03_FIFO_REGS_SIZE;
res = drm_addmap(dev, init.ctrl, init.ctrl_size, _DRM_REGISTERS,
- 0, &dev_priv->fifos[init.channel].regs);
+ 0, &chan->regs);
if (res != 0)
return res;
/* pass back FIFO map info to the caller */
- init.cmdbuf = dev_priv->fifos[init.channel].cmdbuf_mem->start;
- init.cmdbuf_size = dev_priv->fifos[init.channel].cmdbuf_mem->size;
+ init.cmdbuf = chan->cmdbuf_mem->start;
+ init.cmdbuf_size = chan->cmdbuf_mem->size;
+
+ /* and the notifier block */
+ init.notifier = chan->notifier_block->start;
+ init.notifier_size = chan->notifier_block->size;
+ res = drm_addmap(dev, init.notifier, init.notifier_size, _DRM_REGISTERS,
+ 0, &chan->notifier_map);
+ if (res != 0)
+ return res;
DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_alloc_t __user *)data,
init, sizeof(init));
@@ -444,8 +473,8 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS)
drm_ioctl_desc_t nouveau_ioctls[] = {
[DRM_IOCTL_NR(DRM_NOUVEAU_FIFO_ALLOC)] = {nouveau_ioctl_fifo_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_NOUVEAU_OBJECT_INIT)] = {nouveau_ioctl_object_init, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_NOUVEAU_DMA_OBJECT_INIT)] = {nouveau_ioctl_dma_object_init, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_NOUVEAU_GROBJ_ALLOC)] = {nouveau_ioctl_grobj_alloc, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_NOUVEAU_NOTIFIER_ALLOC)] = {nouveau_ioctl_notifier_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_MEM_ALLOC)] = {nouveau_ioctl_mem_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_MEM_FREE)] = {nouveau_ioctl_mem_free, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_GETPARAM)] = {nouveau_ioctl_getparam, DRM_AUTH},
diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c
index a5343b99..edfc9d3f 100644
--- a/shared-core/nouveau_mem.c
+++ b/shared-core/nouveau_mem.c
@@ -77,8 +77,8 @@ out:
return p;
}
-static struct mem_block *alloc_block(struct mem_block *heap, uint64_t size,
- int align2, DRMFILE filp)
+struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size,
+ int align2, DRMFILE filp)
{
struct mem_block *p;
uint64_t mask = (1 << align2) - 1;
@@ -106,7 +106,7 @@ static struct mem_block *find_block(struct mem_block *heap, uint64_t start)
return NULL;
}
-static void free_block(struct mem_block *p)
+void nouveau_mem_free_block(struct mem_block *p)
{
p->filp = NULL;
@@ -132,7 +132,8 @@ static void free_block(struct mem_block *p)
/* Initialize. How to check for an uninitialized heap?
*/
-static int init_heap(struct mem_block **heap, uint64_t start, uint64_t size)
+int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start,
+ uint64_t size)
{
struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS);
@@ -331,7 +332,9 @@ int nouveau_mem_init(struct drm_device *dev)
goto no_agp;
}
- if (init_heap(&dev_priv->agp_heap, info.aperture_base, info.aperture_size))
+ if (nouveau_mem_init_heap(&dev_priv->agp_heap,
+ info.aperture_base,
+ info.aperture_size))
goto no_agp;
dev_priv->agp_phys = info.aperture_base;
@@ -357,12 +360,19 @@ no_agp:
if (fb_size>256*1024*1024) {
/* On cards with > 256Mb, you can't map everything.
* So we create a second FB heap for that type of memory */
- if (init_heap(&dev_priv->fb_heap, drm_get_resource_start(dev,1), 256*1024*1024))
+ if (nouveau_mem_init_heap(&dev_priv->fb_heap,
+ drm_get_resource_start(dev,1),
+ 256*1024*1024))
return DRM_ERR(ENOMEM);
- if (init_heap(&dev_priv->fb_nomap_heap, drm_get_resource_start(dev,1)+256*1024*1024, fb_size-256*1024*1024))
+ if (nouveau_mem_init_heap(&dev_priv->fb_nomap_heap,
+ drm_get_resource_start(dev,1) +
+ 256*1024*1024,
+ fb_size-256*1024*1024))
return DRM_ERR(ENOMEM);
} else {
- if (init_heap(&dev_priv->fb_heap, drm_get_resource_start(dev,1), fb_size))
+ if (nouveau_mem_init_heap(&dev_priv->fb_heap,
+ drm_get_resource_start(dev,1),
+ fb_size))
return DRM_ERR(ENOMEM);
dev_priv->fb_nomap_heap=NULL;
}
@@ -397,21 +407,25 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, uint6
if (flags&NOUVEAU_MEM_AGP) {
type=NOUVEAU_MEM_AGP;
- block = alloc_block(dev_priv->agp_heap, size, alignment, filp);
+ block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,
+ alignment, filp);
if (block) goto alloc_ok;
}
if (flags&(NOUVEAU_MEM_FB|NOUVEAU_MEM_FB_ACCEPTABLE)) {
type=NOUVEAU_MEM_FB;
if (!(flags&NOUVEAU_MEM_MAPPED)) {
- block = alloc_block(dev_priv->fb_nomap_heap, size, alignment, filp);
+ block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap,
+ size, alignment, filp);
if (block) goto alloc_ok;
}
- block = alloc_block(dev_priv->fb_heap, size, alignment, filp);
+ block = nouveau_mem_alloc_block(dev_priv->fb_heap, size,
+ alignment, filp);
if (block) goto alloc_ok;
}
if (flags&NOUVEAU_MEM_AGP_ACCEPTABLE) {
type=NOUVEAU_MEM_AGP;
- block = alloc_block(dev_priv->agp_heap, size, alignment, filp);
+ block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,
+ alignment, filp);
if (block) goto alloc_ok;
}
@@ -432,7 +446,7 @@ alloc_ok:
ret = drm_addmap(dev, block->start, block->size,
_DRM_FRAME_BUFFER, 0, &block->map);
if (ret) {
- free_block(block);
+ nouveau_mem_free_block(block);
return NULL;
}
}
@@ -446,7 +460,7 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block)
DRM_INFO("freeing 0x%llx\n", block->start);
if (block->flags&NOUVEAU_MEM_MAPPED)
drm_rmmap(dev, block->map);
- free_block(block);
+ nouveau_mem_free_block(block);
}
static void
@@ -549,8 +563,8 @@ int nouveau_instmem_init(struct drm_device *dev)
* the space that was reserved for RAMHT/FC/RO.
*/
offset = dev_priv->ramfc_offset + dev_priv->ramfc_size;
- ret = init_heap(&dev_priv->ramin_heap,
- offset, dev_priv->ramin_size - offset);
+ ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
+ offset, dev_priv->ramin_size - offset);
if (ret) {
dev_priv->ramin_heap = NULL;
DRM_ERROR("Failed to init RAMIN heap\n");
@@ -570,7 +584,8 @@ struct mem_block *nouveau_instmem_alloc(struct drm_device *dev,
return NULL;
}
- block = alloc_block(dev_priv->ramin_heap, size, align, (DRMFILE)-2);
+ block = nouveau_mem_alloc_block(dev_priv->ramin_heap, size, align,
+ (DRMFILE)-2);
if (block) {
block->flags = NOUVEAU_MEM_INSTANCE;
DRM_DEBUG("instance(size=%d, align=%d) alloc'd at 0x%08x\n",
@@ -583,7 +598,7 @@ struct mem_block *nouveau_instmem_alloc(struct drm_device *dev,
void nouveau_instmem_free(struct drm_device *dev, struct mem_block *block)
{
if (dev && block) {
- free_block(block);
+ nouveau_mem_free_block(block);
}
}
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;
+}
+
diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c
index e36568c6..e7528e23 100644
--- a/shared-core/nouveau_object.c
+++ b/shared-core/nouveau_object.c
@@ -153,13 +153,13 @@ nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle)
return hash << 3;
}
-static int
+int
nouveau_ht_object_insert(drm_device_t* dev, int channel, uint32_t handle,
struct nouveau_object *obj)
{
drm_nouveau_private_t *dev_priv=dev->dev_private;
int ht_base = NV_RAMIN + dev_priv->ramht_offset;
- int ht_end = ht_base + dev_priv->ramht_size;
+/* int ht_end = ht_base + dev_priv->ramht_size; */
int o_ofs, ofs;
obj->handle = handle;
@@ -461,115 +461,70 @@ nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj)
drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER);
}
-void nouveau_object_cleanup(drm_device_t *dev, int channel)
-{
- drm_nouveau_private_t *dev_priv=dev->dev_private;
-
- while (dev_priv->fifos[channel].objs) {
- nouveau_object_free(dev, dev_priv->fifos[channel].objs);
- }
-}
-
-int nouveau_ioctl_object_init(DRM_IOCTL_ARGS)
+int
+nouveau_object_init_channel(drm_device_t *dev, int channel,
+ uint32_t vram_handle,
+ uint32_t tt_handle)
{
- DRM_DEVICE;
- drm_nouveau_object_init_t init;
- struct nouveau_object *obj;
-
- DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_object_init_t __user *)
- data, sizeof(init));
-
- if (!nouveau_fifo_owner(dev, filp, init.channel)) {
- DRM_ERROR("pid %d doesn't own channel %d\n",
- DRM_CURRENTPID, init.channel);
- return DRM_ERR(EINVAL);
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_object *gpuobj;
+ int ret;
+
+ /* VRAM ctxdma */
+ gpuobj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY,
+ 0, dev_priv->fb_available_size,
+ NV_DMA_ACCESS_RW,
+ NV_DMA_TARGET_VIDMEM);
+ if (!gpuobj) {
+ DRM_ERROR("Error creating VRAM ctxdma: %d\n", DRM_ERR(ENOMEM));
+ return DRM_ERR(ENOMEM);
}
- //FIXME: check args, only allow trusted objects to be created
-
- if (nouveau_object_handle_find(dev, init.channel, init.handle)) {
- DRM_ERROR("Channel %d: handle 0x%08x already exists\n",
- init.channel, init.handle);
- return DRM_ERR(EINVAL);
+ ret = nouveau_ht_object_insert(dev, channel, vram_handle, gpuobj);
+ if (ret) {
+ DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret);
+ return ret;
}
- obj = nouveau_object_gr_create(dev, init.channel, init.class);
- if (!obj)
+ /* non-AGP unimplemented */
+ if (dev_priv->agp_heap == NULL)
+ return 0;
+
+ /* GART ctxdma */
+ gpuobj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY,
+ 0, dev_priv->agp_available_size,
+ NV_DMA_ACCESS_RW,
+ NV_DMA_TARGET_AGP);
+ if (!gpuobj) {
+ DRM_ERROR("Error creating TT ctxdma: %d\n", DRM_ERR(ENOMEM));
return DRM_ERR(ENOMEM);
+ }
- if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) {
- nouveau_object_free(dev, obj);
- return DRM_ERR(ENOMEM);
+ ret = nouveau_ht_object_insert(dev, channel, tt_handle, gpuobj);
+ if (ret) {
+ DRM_ERROR("Error referencing TT ctxdma: %d\n", ret);
+ return ret;
}
return 0;
}
-static int
-nouveau_dma_object_check_access(drm_device_t *dev,
- drm_nouveau_dma_object_init_t *init)
+void nouveau_object_cleanup(drm_device_t *dev, int channel)
{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- uint64_t limit;
-
- /* Check for known DMA object classes */
- switch (init->class) {
- case NV_CLASS_DMA_IN_MEMORY:
- case NV_CLASS_DMA_FROM_MEMORY:
- case NV_CLASS_DMA_TO_MEMORY:
- break;
- default:
- DRM_ERROR("invalid class = 0x%x\n", init->class);
- return DRM_ERR(EPERM);
- }
-
- /* Check access mode, and translate to NV_DMA_ACCESS_* */
- switch (init->access) {
- case NOUVEAU_MEM_ACCESS_RO:
- init->access = NV_DMA_ACCESS_RO;
- break;
- case NOUVEAU_MEM_ACCESS_WO:
- init->access = NV_DMA_ACCESS_WO;
- break;
- case NOUVEAU_MEM_ACCESS_RW:
- init->access = NV_DMA_ACCESS_RW;
- break;
- default:
- DRM_ERROR("invalid access mode = %d\n", init->access);
- return DRM_ERR(EPERM);
- }
-
- /* Check that request is within the allowed limits of "target" */
- switch (init->target) {
- case NOUVEAU_MEM_FB:
- limit = dev_priv->fb_available_size;
- init->target = NV_DMA_TARGET_VIDMEM;
- break;
- case NOUVEAU_MEM_AGP:
- limit = dev_priv->agp_available_size;
- init->target = NV_DMA_TARGET_AGP;
- break;
- default:
- DRM_ERROR("invalid target = 0x%x\n", init->target);
- return DRM_ERR(EPERM);
- }
+ drm_nouveau_private_t *dev_priv=dev->dev_private;
- if ((init->offset > limit) || (init->offset + init->size) > limit) {
- DRM_ERROR("access out of allowed range (%d,0x%08x,0x%08x)\n",
- init->target, init->offset, init->size);
- return DRM_ERR(EPERM);
+ while (dev_priv->fifos[channel].objs) {
+ nouveau_object_free(dev, dev_priv->fifos[channel].objs);
}
-
- return 0;
}
-int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS)
+int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_nouveau_dma_object_init_t init;
+ drm_nouveau_grobj_alloc_t init;
struct nouveau_object *obj;
- DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_dma_object_init_t __user *)
+ DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_grobj_alloc_t __user *)
data, sizeof(init));
if (!nouveau_fifo_owner(dev, filp, init.channel)) {
@@ -578,8 +533,7 @@ int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS)
return DRM_ERR(EINVAL);
}
- if (nouveau_dma_object_check_access(dev, &init))
- return DRM_ERR(EPERM);
+ //FIXME: check args, only allow trusted objects to be created
if (nouveau_object_handle_find(dev, init.channel, init.handle)) {
DRM_ERROR("Channel %d: handle 0x%08x already exists\n",
@@ -587,13 +541,10 @@ int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS)
return DRM_ERR(EINVAL);
}
- obj = nouveau_object_dma_create(dev, init.channel, init.class,
- init.offset, init.size,
- init.access, init.target);
+ obj = nouveau_object_gr_create(dev, init.channel, init.class);
if (!obj)
return DRM_ERR(ENOMEM);
- obj->handle = init.handle;
if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) {
nouveau_object_free(dev, obj);
return DRM_ERR(ENOMEM);
diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c
index b3562e2f..68392c3a 100644
--- a/shared-core/nouveau_state.c
+++ b/shared-core/nouveau_state.c
@@ -260,9 +260,9 @@ void nouveau_preclose(drm_device_t * dev, DRMFILE filp)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nouveau_fifo_cleanup(dev, filp);
nouveau_mem_release(filp,dev_priv->fb_heap);
nouveau_mem_release(filp,dev_priv->agp_heap);
- nouveau_fifo_cleanup(dev, filp);
}
/* first module load, setup the mmio/fb mapping */
@@ -282,7 +282,6 @@ int nouveau_firstopen(struct drm_device *dev)
int nouveau_load(struct drm_device *dev, unsigned long flags)
{
drm_nouveau_private_t *dev_priv;
- int ret;
if (flags==NV_UNKNOWN)
return DRM_ERR(EINVAL);