nouveau: Various internal and external API changes
authorBen Skeggs <skeggsb@gmail.com>
Mon, 6 Aug 2007 11:45:18 +0000 (21:45 +1000)
committerBen Skeggs <skeggsb@gmail.com>
Mon, 6 Aug 2007 11:45:18 +0000 (21:45 +1000)
1. DRM_NOUVEAU_GPUOBJ_FREE
Used to free GPU objects.  The obvious usage case is for Gr objects,
but notifiers can also be destroyed in the same way.

GPU objects gain a destructor method and private data fields with
this change, so other specialised cases (like notifiers) can be
implemented on top of gpuobjs.

2. DRM_NOUVEAU_CHANNEL_FREE

3. DRM_NOUVEAU_CARD_INIT
Ideally we'd do init during module load, but this isn't currently
possible.  Doing init during firstopen() is bad as X has a love of
opening/closing the DRM many times during startup.  Once the
modesetting-101 branch is merged this can go away.

IRQs are enabled in nouveau_card_init() now, rather than having the
X server call drmCtlInstHandler().  We'll need this for when we give
the kernel module its own channel.

4. DRM_NOUVEAU_GETPARAM
Add CHIPSET_ID value, which will return the chipset id derived
from NV_PMC_BOOT_0.

4. Use list_* in a few places, rather than home-brewed stuff.

linux-core/drmP.h
linux-core/drm_irq.c
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
shared-core/nouveau_object.c
shared-core/nouveau_state.c
shared-core/nv04_instmem.c

index a61efcf..aa56222 100644 (file)
@@ -1075,6 +1075,7 @@ extern void drm_core_reclaim_buffers(struct drm_device *dev,
 extern int drm_control(struct drm_device *dev, void *data,
                       struct drm_file *file_priv);
 extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
+extern int drm_irq_install(struct drm_device *dev);
 extern int drm_irq_uninstall(struct drm_device *dev);
 extern void drm_driver_irq_preinstall(struct drm_device *dev);
 extern void drm_driver_irq_postinstall(struct drm_device *dev);
index fe4316e..25166b6 100644 (file)
@@ -80,7 +80,7 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
  * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
  * before and after the installation.
  */
-static int drm_irq_install(struct drm_device * dev)
+int drm_irq_install(struct drm_device * dev)
 {
        int ret;
        unsigned long sh_flags = 0;
@@ -140,6 +140,7 @@ static int drm_irq_install(struct drm_device * dev)
 
        return 0;
 }
+EXPORT_SYMBOL(drm_irq_install);
 
 /**
  * Uninstall the IRQ handler.
index 4016f00..bfc9bd4 100644 (file)
@@ -25,9 +25,9 @@
 #ifndef __NOUVEAU_DRM_H__
 #define __NOUVEAU_DRM_H__
 
-#define NOUVEAU_DRM_HEADER_PATCHLEVEL 9
+#define NOUVEAU_DRM_HEADER_PATCHLEVEL 10
 
-struct drm_nouveau_fifo_alloc {
+struct drm_nouveau_channel_alloc {
        uint32_t     fb_ctxdma_handle;
        uint32_t     tt_ctxdma_handle;
 
@@ -44,6 +44,10 @@ struct drm_nouveau_fifo_alloc {
        int          notifier_size;
 };
 
+struct drm_nouveau_channel_free {
+       int channel;
+};
+
 struct drm_nouveau_grobj_alloc {
        int      channel;
        uint32_t handle;
@@ -53,7 +57,7 @@ struct drm_nouveau_grobj_alloc {
 #define NOUVEAU_MEM_ACCESS_RO  1
 #define NOUVEAU_MEM_ACCESS_WO  2
 #define NOUVEAU_MEM_ACCESS_RW  3
-struct drm_nouveau_notifier_alloc {
+struct drm_nouveau_notifierobj_alloc {
        int      channel;
        uint32_t handle;
        int      count;
@@ -61,6 +65,11 @@ struct drm_nouveau_notifier_alloc {
        uint32_t offset;
 };
 
+struct drm_nouveau_gpuobj_free {
+       int      channel;
+       uint32_t handle;
+};
+
 #define NOUVEAU_MEM_FB                 0x00000001
 #define NOUVEAU_MEM_AGP                        0x00000002
 #define NOUVEAU_MEM_FB_ACCEPTABLE      0x00000004
@@ -95,6 +104,7 @@ struct drm_nouveau_mem_free {
 #define NOUVEAU_GETPARAM_FB_SIZE         8
 #define NOUVEAU_GETPARAM_AGP_SIZE        9
 #define NOUVEAU_GETPARAM_PCI_PHYSICAL    10
+#define NOUVEAU_GETPARAM_CHIPSET_ID      11
 struct drm_nouveau_getparam {
        uint64_t param;
        uint64_t value;
@@ -141,13 +151,16 @@ struct drm_nouveau_sarea {
        unsigned int nbox;
 };
 
-#define DRM_NOUVEAU_FIFO_ALLOC      0x00
-#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
-#define DRM_NOUVEAU_SETPARAM        0x06
+#define DRM_NOUVEAU_CARD_INIT          0x00
+#define DRM_NOUVEAU_GETPARAM           0x01
+#define DRM_NOUVEAU_SETPARAM           0x02
+#define DRM_NOUVEAU_CHANNEL_ALLOC      0x03
+#define DRM_NOUVEAU_CHANNEL_FREE       0x04
+#define DRM_NOUVEAU_GROBJ_ALLOC        0x05
+#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC  0x06
+#define DRM_NOUVEAU_GPUOBJ_FREE        0x07
+#define DRM_NOUVEAU_MEM_ALLOC          0x08
+#define DRM_NOUVEAU_MEM_FREE           0x09
 
 #endif /* __NOUVEAU_DRM_H__ */
 
index 8ec9189..0b173b7 100644 (file)
@@ -34,7 +34,7 @@
 
 #define DRIVER_MAJOR           0
 #define DRIVER_MINOR           0
-#define DRIVER_PATCHLEVEL      9
+#define DRIVER_PATCHLEVEL      10
 
 #define NOUVEAU_FAMILY   0x0000FFFF
 #define NOUVEAU_FLAGS    0xFFFF0000
@@ -67,8 +67,7 @@ enum nouveau_flags {
 #define NVOBJ_FLAG_ZERO_FREE           (1 << 2)
 #define NVOBJ_FLAG_FAKE                        (1 << 3)
 struct nouveau_gpuobj {
-       struct nouveau_gpuobj *next;
-       struct nouveau_gpuobj *prev;
+       struct list_head list;
 
        int im_channel;
        struct mem_block *im_pramin;
@@ -80,10 +79,13 @@ struct nouveau_gpuobj {
 
        uint32_t engine;
        uint32_t class;
+
+       void (*dtor)(struct drm_device *, struct nouveau_gpuobj *);
+       void *priv;
 };
 
 struct nouveau_gpuobj_ref {
-       struct nouveau_gpuobj_ref *next;
+       struct list_head list;
 
        struct nouveau_gpuobj *gpuobj;
        uint32_t instance;
@@ -129,7 +131,7 @@ struct nouveau_channel
        struct nouveau_gpuobj_ref *ramin; /* Private instmem */
        struct mem_block          *ramin_heap; /* Private PRAMIN heap */
        struct nouveau_gpuobj_ref *ramht; /* Hash table */
-       struct nouveau_gpuobj_ref *ramht_refs; /* Objects referenced by RAMHT */
+       struct list_head           ramht_refs; /* Objects referenced by RAMHT */
 };
 
 struct nouveau_config {
@@ -269,9 +271,17 @@ struct drm_nouveau_private {
 
        struct nouveau_config config;
 
-       struct nouveau_gpuobj *gpuobj_all;
+       struct list_head gpuobj_list;
 };
 
+#define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do {         \
+       struct drm_nouveau_private *nv = dev->dev_private; \
+       if (nv->init_state != NOUVEAU_CARD_INIT_DONE) {    \
+               DRM_ERROR("called without init\n");        \
+               return -EINVAL;                            \
+       }                                                  \
+} while(0)
+
 #define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id,cl,ch) do {  \
        struct drm_nouveau_private *nv = dev->dev_private;   \
        if (!nouveau_fifo_owner(dev, (cl), (id))) {          \
@@ -293,6 +303,7 @@ extern int  nouveau_ioctl_getparam(struct drm_device *, void *data,
 extern int  nouveau_ioctl_setparam(struct drm_device *, void *data,
                                   struct drm_file *);
 extern void nouveau_wait_for_idle(struct drm_device *);
+extern int  nouveau_card_init(struct drm_device *);
 extern int  nouveau_ioctl_card_init(struct drm_device *, void *data,
                                    struct drm_file *);
 
@@ -324,6 +335,8 @@ extern int  nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle,
                                   int cout, uint32_t *offset);
 extern int  nouveau_ioctl_notifier_alloc(struct drm_device *, void *data,
                                         struct drm_file *);
+extern int  nouveau_ioctl_notifier_free(struct drm_device *, void *data,
+                                       struct drm_file *);
 
 /* nouveau_fifo.c */
 extern int  nouveau_fifo_init(struct drm_device *);
@@ -335,6 +348,7 @@ extern int  nouveau_fifo_owner(struct drm_device *, struct drm_file *,
 extern void nouveau_fifo_free(struct nouveau_channel *);
 
 /* nouveau_object.c */
+extern int  nouveau_gpuobj_init(struct drm_device *);
 extern void nouveau_gpuobj_takedown(struct drm_device *);
 extern int nouveau_gpuobj_channel_init(struct nouveau_channel *,
                                       uint32_t vram_h, uint32_t tt_h);
@@ -348,6 +362,8 @@ extern int nouveau_gpuobj_ref_add(struct drm_device *, struct nouveau_channel *,
                                  struct nouveau_gpuobj_ref **);
 extern int nouveau_gpuobj_ref_del(struct drm_device *,
                                  struct nouveau_gpuobj_ref **);
+extern int nouveau_gpuobj_ref_find(struct nouveau_channel *, uint32_t handle,
+                                  struct nouveau_gpuobj_ref **ref_ret);
 extern int nouveau_gpuobj_new_ref(struct drm_device *,
                                  struct nouveau_channel *alloc_chan,
                                  struct nouveau_channel *ref_chan,
@@ -368,6 +384,8 @@ extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class,
                                 struct nouveau_gpuobj **);
 extern int nouveau_ioctl_grobj_alloc(struct drm_device *, void *data,
                                     struct drm_file *);
+extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data,
+                                    struct drm_file *);
 
 /* nouveau_irq.c */
 extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS);
index c7ce1d8..152b669 100644 (file)
@@ -302,22 +302,22 @@ int nouveau_fifo_alloc(struct drm_device *dev, int *chan_ret,
 
        DRM_INFO("Allocating FIFO number %d\n", channel);
 
-       /* Setup channel's default objects */
-       ret = nouveau_gpuobj_channel_init(chan, vram_handle, tt_handle);
+       /* Allocate space for per-channel fixed notifier memory */
+       ret = nouveau_notifier_init_channel(chan);
        if (ret) {
                nouveau_fifo_free(chan);
                return ret;
        }
 
-       /* allocate a command buffer, and create a dma object for the gpu */
-       ret = nouveau_fifo_cmdbuf_alloc(chan);
+       /* Setup channel's default objects */
+       ret = nouveau_gpuobj_channel_init(chan, vram_handle, tt_handle);
        if (ret) {
                nouveau_fifo_free(chan);
                return ret;
        }
 
-       /* Allocate space for per-channel fixed notifier memory */
-       ret = nouveau_notifier_init_channel(chan);
+       /* allocate a command buffer, and create a dma object for the gpu */
+       ret = nouveau_fifo_cmdbuf_alloc(chan);
        if (ret) {
                nouveau_fifo_free(chan);
                return ret;
@@ -426,11 +426,11 @@ void nouveau_fifo_free(struct nouveau_channel *chan)
                chan->pushbuf_mem = NULL;
        }
 
-       nouveau_notifier_takedown_channel(chan);
-
        /* Destroy objects belonging to the channel */
        nouveau_gpuobj_channel_takedown(chan);
 
+       nouveau_notifier_takedown_channel(chan);
+
        dev_priv->fifos[chan->id] = NULL;
        dev_priv->fifo_alloc_count--;
        drm_free(chan, sizeof(*chan), DRM_MEM_DRIVER);
@@ -468,14 +468,17 @@ nouveau_fifo_owner(struct drm_device *dev, struct drm_file *file_priv,
  * ioctls wrapping the functions
  ***********************************/
 
-static int nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
+static int nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct drm_nouveau_fifo_alloc *init = data;
+       struct drm_nouveau_channel_alloc *init = data;
        struct drm_map_list *entry;
        struct nouveau_channel *chan;
        int res;
 
+       NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
+
        if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
                return -EINVAL;
 
@@ -519,18 +522,34 @@ static int nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, struct d
        return 0;
 }
 
+static int nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
+                                  struct drm_file *file_priv)
+{
+       struct drm_nouveau_channel_free *cfree = data;
+       struct nouveau_channel *chan;
+
+       NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
+       NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan);
+
+       nouveau_fifo_free(chan);
+       return 0;
+}
+
 /***********************************
  * finally, the ioctl table
  ***********************************/
 
 struct drm_ioctl_desc nouveau_ioctls[] = {
-       DRM_IOCTL_DEF(DRM_NOUVEAU_FIFO_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_NOUVEAU_CARD_INIT, nouveau_ioctl_card_init, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_NOUVEAU_NOTIFIER_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_ALLOC, nouveau_ioctl_mem_alloc, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_FREE, nouveau_ioctl_mem_free, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 };
 
 int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls);
index a7044c9..981af8a 100644 (file)
@@ -549,14 +549,10 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block)
 
 int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct drm_nouveau_mem_alloc *alloc = data;
        struct mem_block *block;
 
-       if (!dev_priv) {
-               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-               return -EINVAL;
-       }
+       NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
 
        block=nouveau_mem_alloc(dev, alloc->alignment, alloc->size,
                                alloc->flags, file_priv);
@@ -575,6 +571,8 @@ int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file *
        struct drm_nouveau_mem_free *memfree = data;
        struct mem_block *block;
 
+       NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
+
        block=NULL;
        if (memfree->flags & NOUVEAU_MEM_FB)
                block = find_block(dev_priv->fb_heap, memfree->offset);
index b109058..31547aa 100644 (file)
@@ -73,6 +73,16 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
        nouveau_mem_takedown(&chan->notifier_heap);
 }
 
+static void
+nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
+                            struct nouveau_gpuobj *gpuobj)
+{
+       DRM_DEBUG("\n");
+
+       if (gpuobj->priv)
+               nouveau_mem_free_block(gpuobj->priv);
+}
+
 int
 nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
                       int count, uint32_t *b_offset)
@@ -90,7 +100,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
        }
 
        mem = nouveau_mem_alloc_block(chan->notifier_heap, 32, 0,
-                                     chan->file_priv);
+                                     (struct drm_file *)-2);
        if (!mem) {
                DRM_ERROR("Channel %d notifier block full\n", chan->id);
                return -ENOMEM;
@@ -117,6 +127,8 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
                DRM_ERROR("Error creating notifier ctxdma: %d\n", ret);
                return ret;
        }
+       nobj->dtor   = nouveau_notifier_gpuobj_dtor;
+       nobj->priv   = mem;
 
        if ((ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL))) {
                nouveau_gpuobj_del(dev, &nobj);
@@ -133,10 +145,11 @@ int
 nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
                             struct drm_file *file_priv)
 {
-       struct drm_nouveau_notifier_alloc *na = data;
+       struct drm_nouveau_notifierobj_alloc *na = data;
        struct nouveau_channel *chan;
        int ret;
 
+       NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
        NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan);
 
        ret = nouveau_notifier_alloc(chan, na->handle, na->count, &na->offset);
index 274bb2a..22ad23c 100644 (file)
@@ -131,6 +131,8 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
                                  ref->channel, co, ref->handle, ctx);
                        INSTANCE_WR(ramht, (co + 0)/4, ref->handle);
                        INSTANCE_WR(ramht, (co + 4)/4, ctx);
+
+                       list_add_tail(&ref->list, &chan->ramht_refs);
                        return 0;
                }
                DRM_DEBUG("collision ch%d 0x%08x: h=0x%08x\n",
@@ -167,6 +169,8 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
                                  INSTANCE_RD(ramht, (co + 4)));
                        INSTANCE_WR(ramht, (co + 0)/4, 0x00000000);
                        INSTANCE_WR(ramht, (co + 4)/4, 0x00000000);
+
+                       list_del(&ref->list);
                        return;
                }
 
@@ -203,6 +207,8 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
        gpuobj->flags = flags;
        gpuobj->im_channel = chan ? chan->id : -1;
 
+       list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+
        /* Choose between global instmem heap, and per-channel private
         * instmem heap.  On <NV50 allow requests for private instmem
         * to be satisfied from global heap if no per-channel area
@@ -254,24 +260,44 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
                        INSTANCE_WR(gpuobj, i/4, 0);
        }
 
-       if (dev_priv->gpuobj_all) {
-               gpuobj->next = dev_priv->gpuobj_all;
-               gpuobj->next->prev = gpuobj;
+       *gpuobj_ret = gpuobj;
+       return 0;
+}
+
+int
+nouveau_gpuobj_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       int ret;
+
+       INIT_LIST_HEAD(&dev_priv->gpuobj_list);
+
+       if (dev_priv->card_type < NV_50) {
+               if ((ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset,
+                                                  dev_priv->ramht_size,
+                                                  NVOBJ_FLAG_ZERO_ALLOC |
+                                                  NVOBJ_FLAG_ALLOW_NO_REFS,
+                                                  &dev_priv->ramht, NULL)))
+                       return ret;
        }
-       dev_priv->gpuobj_all = gpuobj;
 
-       *gpuobj_ret = gpuobj;
        return 0;
 }
 
-void nouveau_gpuobj_takedown(struct drm_device *dev)
+void
+nouveau_gpuobj_takedown(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_gpuobj *gpuobj = NULL;
+       struct list_head *entry, *tmp;
 
        DRM_DEBUG("\n");
 
-       while ((gpuobj = dev_priv->gpuobj_all)) {
+       nouveau_gpuobj_del(dev, &dev_priv->ramht);
+
+       list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) {
+               gpuobj = list_entry(entry, struct nouveau_gpuobj, list);
+
                DRM_ERROR("gpuobj %p still exists at takedown, refs=%d\n",
                          gpuobj, gpuobj->refcount);
                gpuobj->refcount = 0;
@@ -279,7 +305,8 @@ void nouveau_gpuobj_takedown(struct drm_device *dev)
        }
 }
 
-int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
+int
+nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->Engine;
@@ -296,6 +323,9 @@ int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
                return -EINVAL;
        }
 
+       if (gpuobj->dtor)
+               gpuobj->dtor(dev, gpuobj);
+
        engine->instmem.clear(dev, gpuobj);
 
        if (gpuobj->im_pramin) {
@@ -306,12 +336,7 @@ int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
                        nouveau_mem_free_block(gpuobj->im_pramin);
        }
 
-       if (gpuobj->next)
-               gpuobj->next->prev = gpuobj->prev;
-       if (gpuobj->prev)
-               gpuobj->prev->next = gpuobj->next;
-       else
-               dev_priv->gpuobj_all = gpuobj->next;
+       list_del(&gpuobj->list);
 
        *pgpuobj = NULL;
        drm_free(gpuobj, sizeof(*gpuobj), DRM_MEM_DRIVER);
@@ -403,9 +428,6 @@ nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan,
                        drm_free(ref, sizeof(*ref), DRM_MEM_DRIVER);
                        return ret;
                }
-
-               ref->next = chan->ramht_refs;
-               chan->ramht_refs = ref;
        } else {
                ref->handle = ~0;
                *ref_ret = ref;
@@ -462,19 +484,21 @@ nouveau_gpuobj_new_ref(struct drm_device *dev,
        return 0;
 }
 
-static int
+int
 nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle,
                        struct nouveau_gpuobj_ref **ref_ret)
 {
-       struct nouveau_gpuobj_ref *ref = chan->ramht_refs;
+       struct nouveau_gpuobj_ref *ref;
+       struct list_head *entry, *tmp;
+
+       list_for_each_safe(entry, tmp, &chan->ramht_refs) {             
+               ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
 
-       while (ref) {
                if (ref->handle == handle) {
                        if (ref_ret)
                                *ref_ret = ref;
                        return 0;
                }
-               ref = ref->next;
        }
 
        return -EINVAL;
@@ -499,6 +523,8 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size,
        gpuobj->im_channel = -1;
        gpuobj->flags      = flags | NVOBJ_FLAG_FAKE;
 
+       list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+
        gpuobj->im_pramin = drm_calloc(1, sizeof(struct mem_block),
                                       DRM_MEM_DRIVER);
        if (!gpuobj->im_pramin) {
@@ -897,6 +923,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
        struct nouveau_gpuobj *vram = NULL, *tt = NULL;
        int ret, i;
 
+       INIT_LIST_HEAD(&chan->ramht_refs);
+
        DRM_DEBUG("ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
 
        /* Reserve a block of PRAMIN for the channel
@@ -994,14 +1022,17 @@ void
 nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
+       struct list_head *entry, *tmp;
        struct nouveau_gpuobj_ref *ref;
 
        DRM_DEBUG("ch%d\n", chan->id);
 
-       while ((ref = chan->ramht_refs)) {
-               chan->ramht_refs = ref->next;
+       list_for_each_safe(entry, tmp, &chan->ramht_refs) {             
+               ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
+
                nouveau_gpuobj_ref_del(dev, &ref);
        }
+
        nouveau_gpuobj_ref_del(dev, &chan->ramht);
 
        nouveau_gpuobj_del(dev, &chan->vm_pd);
@@ -1022,6 +1053,7 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
        struct nouveau_gpuobj *gr = NULL;
        int ret;
 
+       NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
        NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan);
 
        //FIXME: check args, only allow trusted objects to be created
@@ -1029,8 +1061,7 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
        if (init->handle == ~0)
                return -EINVAL;
 
-       if (nouveau_gpuobj_ref_find(chan, init->handle, NULL) ==
-           0)
+       if (nouveau_gpuobj_ref_find(chan, init->handle, NULL) == 0)
                return -EEXIST;
 
        ret = nouveau_gpuobj_gr_new(chan, init->class, &gr);
@@ -1050,3 +1081,21 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
        return 0;
 }
 
+int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
+{
+       struct drm_nouveau_gpuobj_free *objfree = data;
+       struct nouveau_gpuobj_ref *ref;
+       struct nouveau_channel *chan;
+       int ret;
+
+       NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
+       NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan);
+
+       if ((ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref)))
+               return ret;
+       nouveau_gpuobj_ref_del(dev, &ref);
+
+       return 0;
+}
+
index 26ba8fb..4fb5329 100644 (file)
@@ -267,12 +267,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
        return 0;
 }
 
-static int nouveau_card_init(struct drm_device *dev)
+int
+nouveau_card_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine;
        int ret;
 
+       if (dev_priv->init_state == NOUVEAU_CARD_INIT_DONE)
+               return 0;
+
        /* Map any PCI resources we need on the card */
        ret = nouveau_init_card_mappings(dev);
        if (ret) return ret;
@@ -290,6 +294,9 @@ static int nouveau_card_init(struct drm_device *dev)
        engine = &dev_priv->Engine;
        dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
 
+       ret = drm_irq_install(dev);
+       if (ret) return ret;
+
        /* Initialise instance memory, must happen before mem_init so we
         * know exactly how much VRAM we're able to use for "normal"
         * purposes.
@@ -301,6 +308,9 @@ static int nouveau_card_init(struct drm_device *dev)
        ret = nouveau_mem_init(dev);
        if (ret) return ret;
 
+       ret = nouveau_gpuobj_init(dev);
+       if (ret) return ret;
+
        /* Parse BIOS tables / Run init tables? */
 
        /* PMC */
@@ -349,6 +359,8 @@ static void nouveau_card_takedown(struct drm_device *dev)
                nouveau_mem_close(dev);
                engine->instmem.takedown(dev);
 
+               drm_irq_uninstall(dev);
+
                dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
        }
 }
@@ -368,14 +380,6 @@ void nouveau_preclose(struct drm_device *dev, struct drm_file *file_priv)
 /* first module load, setup the mmio/fb mapping */
 int nouveau_firstopen(struct drm_device *dev)
 {
-       int ret;
-
-       ret = nouveau_card_init(dev);
-       if (ret) {
-               DRM_ERROR("nouveau_card_init() failed! (%d)\n", ret);
-               return ret;
-       }
-
        return 0;
 }
 
@@ -395,15 +399,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
        dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
 
        dev->dev_private = (void *)dev_priv;
-
-#if 0
-       ret = nouveau_card_init(dev);
-       if (ret) {
-               DRM_ERROR("nouveau_card_init() failed! (%d)\n", ret);
-               return ret;
-       }
-#endif
-
        return 0;
 }
 
@@ -427,12 +422,24 @@ int nouveau_unload(struct drm_device *dev)
        return 0;
 }
 
+int
+nouveau_ioctl_card_init(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       return nouveau_card_init(dev);
+}
+
 int nouveau_ioctl_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct drm_nouveau_getparam *getparam = data;
 
+       NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
+
        switch (getparam->param) {
+       case NOUVEAU_GETPARAM_CHIPSET_ID:
+               getparam->value = dev_priv->chipset;
+               break;
        case NOUVEAU_GETPARAM_PCI_VENDOR:
                getparam->value=dev->pci_vendor;
                break;
@@ -481,6 +488,8 @@ int nouveau_ioctl_setparam(struct drm_device *dev, void *data, struct drm_file *
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct drm_nouveau_setparam *setparam = data;
 
+       NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
+
        switch (setparam->param) {
        case NOUVEAU_SETPARAM_CMDBUF_LOCATION:
                switch (setparam->value) {
index 35b20ab..36aa620 100644 (file)
@@ -93,13 +93,6 @@ int nv04_instmem_init(struct drm_device *dev)
        nv04_instmem_determine_amount(dev);
        nv04_instmem_configure_fixed_tables(dev);
 
-       if ((ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset,
-                                               dev_priv->ramht_size,
-                                               NVOBJ_FLAG_ZERO_ALLOC |
-                                               NVOBJ_FLAG_ALLOW_NO_REFS,
-                                               &dev_priv->ramht, NULL)))
-               return ret;
-
        /* Create a heap to manage RAMIN allocations, we don't allocate
         * the space that was reserved for RAMHT/FC/RO.
         */
@@ -117,9 +110,6 @@ int nv04_instmem_init(struct drm_device *dev)
 void
 nv04_instmem_takedown(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       nouveau_gpuobj_del(dev, &dev_priv->ramht);
 }
 
 int