OSDN Git Service

nouveau: Nuke DMA_OBJECT_INIT ioctl (bumps interface to 0.0.7)
authorBen Skeggs <skeggsb@gmail.com>
Sun, 24 Jun 2007 09:03:35 +0000 (19:03 +1000)
committerBen Skeggs <skeggsb@gmail.com>
Wed, 27 Jun 2007 17:26:43 +0000 (03:26 +1000)
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.

linux-core/Makefile.kernel
linux-core/nouveau_notifier.c [new symlink]
shared-core/nouveau_drm.h
shared-core/nouveau_drv.h
shared-core/nouveau_fifo.c
shared-core/nouveau_mem.c
shared-core/nouveau_notifier.c [new file with mode: 0644]
shared-core/nouveau_object.c
shared-core/nouveau_state.c

index 9427a04..6ab17a4 100644 (file)
@@ -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 (symlink)
index 0000000..285469c
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/nouveau_notifier.c
\ No newline at end of file
index 1e7322e..0758991 100644 (file)
 #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
index b3122d8..7a1ca3d 100644 (file)
@@ -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 */
index 1a06f91..f179af6 100644 (file)
@@ -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},
index a5343b9..edfc9d3 100644 (file)
@@ -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 (file)
index 0000000..ab6f8c2
--- /dev/null
@@ -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;
+}
+
index e36568c..e7528e2 100644 (file)
@@ -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);
index b3562e2..68392c3 100644 (file)
@@ -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);