summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <skeggsb@gmail.com>2007-08-06 21:45:18 +1000
committerBen Skeggs <skeggsb@gmail.com>2007-08-06 21:45:18 +1000
commit97770db72040dc032130413e0cdabc1777560a75 (patch)
treea3b31266e5049c059ba8e9146a911a6bda402efe
parentbeaa0c9a28b30a6ba3292184d04875b6a597e433 (diff)
nouveau: Various internal and external API changes
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.
-rw-r--r--linux-core/drmP.h1
-rw-r--r--linux-core/drm_irq.c3
-rw-r--r--shared-core/nouveau_drm.h33
-rw-r--r--shared-core/nouveau_drv.h30
-rw-r--r--shared-core/nouveau_fifo.c47
-rw-r--r--shared-core/nouveau_mem.c8
-rw-r--r--shared-core/nouveau_notifier.c17
-rw-r--r--shared-core/nouveau_object.c99
-rw-r--r--shared-core/nouveau_state.c45
-rw-r--r--shared-core/nv04_instmem.c10
10 files changed, 202 insertions, 91 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index a61efcff..aa562225 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -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);
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index fe4316e0..25166b6f 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -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.
diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h
index 4016f004..bfc9bd4b 100644
--- a/shared-core/nouveau_drm.h
+++ b/shared-core/nouveau_drm.h
@@ -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__ */
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index 8ec91898..0b173b76 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 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);
diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c
index c7ce1d8d..152b669a 100644
--- a/shared-core/nouveau_fifo.c
+++ b/shared-core/nouveau_fifo.c
@@ -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);
diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c
index a7044c94..981af8a6 100644
--- a/shared-core/nouveau_mem.c
+++ b/shared-core/nouveau_mem.c
@@ -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);
diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c
index b1090587..31547aae 100644
--- a/shared-core/nouveau_notifier.c
+++ b/shared-core/nouveau_notifier.c
@@ -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);
diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c
index 274bb2a7..22ad23cd 100644
--- a/shared-core/nouveau_object.c
+++ b/shared-core/nouveau_object.c
@@ -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;
+}
+
diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c
index 26ba8fbf..4fb53291 100644
--- a/shared-core/nouveau_state.c
+++ b/shared-core/nouveau_state.c
@@ -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) {
diff --git a/shared-core/nv04_instmem.c b/shared-core/nv04_instmem.c
index 35b20abd..36aa6200 100644
--- a/shared-core/nv04_instmem.c
+++ b/shared-core/nv04_instmem.c
@@ -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