summaryrefslogtreecommitdiff
path: root/shared-core/nouveau_object.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared-core/nouveau_object.c')
-rw-r--r--shared-core/nouveau_object.c322
1 files changed, 203 insertions, 119 deletions
diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c
index e8b12bb7..fbce7702 100644
--- a/shared-core/nouveau_object.c
+++ b/shared-core/nouveau_object.c
@@ -72,6 +72,8 @@ nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle)
uint32_t hash = 0;
int i;
+ DRM_DEBUG("ch%d handle=0x%08x\n", channel, handle);
+
for (i=32;i>0;i-=dev_priv->ramht_bits) {
hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1));
handle >>= dev_priv->ramht_bits;
@@ -80,7 +82,7 @@ nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle)
hash ^= channel << (dev_priv->ramht_bits - 4);
hash <<= 3;
- DRM_DEBUG("ch%d handle=0x%08x hash=0x%08x\n", channel, handle, hash);
+ DRM_DEBUG("hash=0x%08x\n", hash);
return hash;
}
@@ -100,7 +102,7 @@ static int
nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
{
struct drm_nouveau_private *dev_priv=dev->dev_private;
- struct nouveau_fifo *chan = dev_priv->fifos[ref->channel];
+ struct nouveau_channel *chan = dev_priv->fifos[ref->channel];
struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
struct nouveau_gpuobj *gpuobj = ref->gpuobj;
uint32_t ctx, co, ho;
@@ -131,14 +133,21 @@ 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",
ref->channel, co, INSTANCE_RD(ramht, co/4));
co += 8;
- if (co >= dev_priv->ramht_size)
+ if (co >= dev_priv->ramht_size) {
+ DRM_INFO("no space left after collision\n");
co = 0;
+ /* exit as it seems to cause crash with nouveau_demo and
+ * 0xdead0001 object */
+ break;
+ }
} while (co != ho);
DRM_ERROR("RAMHT space exhausted. ch=%d\n", ref->channel);
@@ -149,7 +158,7 @@ static void
nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo *chan = dev_priv->fifos[ref->channel];
+ struct nouveau_channel *chan = dev_priv->fifos[ref->channel];
struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
uint32_t co, ho;
@@ -167,6 +176,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;
}
@@ -180,34 +191,30 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
}
int
-nouveau_gpuobj_new(struct drm_device *dev, int channel, int size, int align,
- uint32_t flags, struct nouveau_gpuobj **gpuobj_ret)
+nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
+ int size, int align, uint32_t flags,
+ struct nouveau_gpuobj **gpuobj_ret)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_engine_func *engine = &dev_priv->Engine;
- struct nouveau_fifo *chan = NULL;
+ struct nouveau_engine *engine = &dev_priv->Engine;
struct nouveau_gpuobj *gpuobj;
struct mem_block *pramin = NULL;
int ret;
DRM_DEBUG("ch%d size=%d align=%d flags=0x%08x\n",
- channel, size, align, flags);
+ chan ? chan->id : -1, size, align, flags);
if (!dev_priv || !gpuobj_ret || *gpuobj_ret != NULL)
return -EINVAL;
- if (channel >= 0) {
- if (channel > nouveau_fifo_number(dev))
- return -EINVAL;
- chan = dev_priv->fifos[channel];
- }
-
gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER);
if (!gpuobj)
return -ENOMEM;
DRM_DEBUG("gpuobj %p\n", gpuobj);
gpuobj->flags = flags;
- gpuobj->im_channel = channel;
+ 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
@@ -260,24 +267,64 @@ nouveau_gpuobj_new(struct drm_device *dev, int channel, int size, int align,
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_early_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ DRM_DEBUG("\n");
+
+ INIT_LIST_HEAD(&dev_priv->gpuobj_list);
+
+ return 0;
+}
+
+int
+nouveau_gpuobj_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int ret;
+
+ DRM_DEBUG("\n");
+
+ if (dev_priv->card_type < NV_50) {
+ if ((ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset,
+ ~0, 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;
+
+ DRM_DEBUG("\n");
+
+ nouveau_gpuobj_del(dev, &dev_priv->ramht);
+}
+
+void
+nouveau_gpuobj_late_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)) {
+ 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;
@@ -285,10 +332,11 @@ 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_func *engine = &dev_priv->Engine;
+ struct nouveau_engine *engine = &dev_priv->Engine;
struct nouveau_gpuobj *gpuobj;
DRM_DEBUG("gpuobj %p\n", pgpuobj ? *pgpuobj : NULL);
@@ -302,7 +350,16 @@ int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
return -EINVAL;
}
- engine->instmem.clear(dev, gpuobj);
+ if (gpuobj->dtor)
+ gpuobj->dtor(dev, gpuobj);
+
+ if (gpuobj->im_backing) {
+ if (gpuobj->flags & NVOBJ_FLAG_FAKE)
+ drm_free(gpuobj->im_backing,
+ sizeof(*gpuobj->im_backing), DRM_MEM_DRIVER);
+ else
+ engine->instmem.clear(dev, gpuobj);
+ }
if (gpuobj->im_pramin) {
if (gpuobj->flags & NVOBJ_FLAG_FAKE)
@@ -312,12 +369,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);
@@ -325,7 +377,8 @@ int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
}
static int
-nouveau_gpuobj_instance_get(struct drm_device *dev, int channel,
+nouveau_gpuobj_instance_get(struct drm_device *dev,
+ struct nouveau_channel *chan,
struct nouveau_gpuobj *gpuobj, uint32_t *inst)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -337,15 +390,15 @@ nouveau_gpuobj_instance_get(struct drm_device *dev, int channel,
return 0;
}
- if ((channel > 0) && gpuobj->im_channel != channel) {
+ if (chan && gpuobj->im_channel != chan->id) {
DRM_ERROR("Channel mismatch: obj %d, ref %d\n",
- gpuobj->im_channel, channel);
+ gpuobj->im_channel, chan->id);
return -EINVAL;
}
/* NV50 channel-local instance */
- if (channel > 0) {
- cpramin = dev_priv->fifos[channel]->ramin->gpuobj;
+ if (chan > 0) {
+ cpramin = chan->ramin->gpuobj;
*inst = gpuobj->im_pramin->start - cpramin->im_pramin->start;
return 0;
}
@@ -371,29 +424,25 @@ nouveau_gpuobj_instance_get(struct drm_device *dev, int channel,
}
int
-nouveau_gpuobj_ref_add(struct drm_device *dev, int channel, uint32_t handle,
- struct nouveau_gpuobj *gpuobj, struct nouveau_gpuobj_ref **ref_ret)
+nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan,
+ uint32_t handle, struct nouveau_gpuobj *gpuobj,
+ struct nouveau_gpuobj_ref **ref_ret)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo *chan = NULL;
struct nouveau_gpuobj_ref *ref;
uint32_t instance;
int ret;
- DRM_DEBUG("ch%d h=0x%08x gpuobj=%p\n", channel, handle, gpuobj);
+ DRM_DEBUG("ch%d h=0x%08x gpuobj=%p\n",
+ chan ? chan->id : -1, handle, gpuobj);
if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL))
return -EINVAL;
- if (channel >= 0) {
- if (channel > nouveau_fifo_number(dev))
- return -EINVAL;
- chan = dev_priv->fifos[channel];
- } else
- if (!ref_ret)
+ if (!chan && !ref_ret)
return -EINVAL;
- ret = nouveau_gpuobj_instance_get(dev, channel, gpuobj, &instance);
+ ret = nouveau_gpuobj_instance_get(dev, chan, gpuobj, &instance);
if (ret)
return ret;
@@ -401,7 +450,7 @@ nouveau_gpuobj_ref_add(struct drm_device *dev, int channel, uint32_t handle,
if (!ref)
return -ENOMEM;
ref->gpuobj = gpuobj;
- ref->channel = channel;
+ ref->channel = chan ? chan->id : -1;
ref->instance = instance;
if (!ref_ret) {
@@ -412,9 +461,6 @@ nouveau_gpuobj_ref_add(struct drm_device *dev, int channel, uint32_t handle,
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;
@@ -452,8 +498,9 @@ int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **p
}
int
-nouveau_gpuobj_new_ref(struct drm_device *dev, int oc, int rc, uint32_t handle,
- int size, int align, uint32_t flags,
+nouveau_gpuobj_new_ref(struct drm_device *dev,
+ struct nouveau_channel *oc, struct nouveau_channel *rc,
+ uint32_t handle, int size, int align, uint32_t flags,
struct nouveau_gpuobj_ref **ref)
{
struct nouveau_gpuobj *gpuobj = NULL;
@@ -470,28 +517,29 @@ nouveau_gpuobj_new_ref(struct drm_device *dev, int oc, int rc, uint32_t handle,
return 0;
}
-static int
-nouveau_gpuobj_ref_find(struct drm_device *dev, int channel, uint32_t handle,
+int
+nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle,
struct nouveau_gpuobj_ref **ref_ret)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo *chan = dev_priv->fifos[channel];
- 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;
}
int
-nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size,
+nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
+ uint32_t b_offset, uint32_t size,
uint32_t flags, struct nouveau_gpuobj **pgpuobj,
struct nouveau_gpuobj_ref **pref)
{
@@ -499,8 +547,8 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size,
struct nouveau_gpuobj *gpuobj = NULL;
int i;
- DRM_DEBUG("offset=0x%08x size=0x%08x flags=0x%08x\n",
- offset, size, flags);
+ DRM_DEBUG("p_offset=0x%08x b_offset=0x%08x size=0x%08x flags=0x%08x\n",
+ p_offset, b_offset, size, flags);
gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER);
if (!gpuobj)
@@ -509,14 +557,29 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size,
gpuobj->im_channel = -1;
gpuobj->flags = flags | NVOBJ_FLAG_FAKE;
- gpuobj->im_pramin = drm_calloc(1, sizeof(struct mem_block),
- DRM_MEM_DRIVER);
- if (!gpuobj->im_pramin) {
- nouveau_gpuobj_del(dev, &gpuobj);
- return -ENOMEM;
+ list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+
+ if (p_offset != ~0) {
+ gpuobj->im_pramin = drm_calloc(1, sizeof(struct mem_block),
+ DRM_MEM_DRIVER);
+ if (!gpuobj->im_pramin) {
+ nouveau_gpuobj_del(dev, &gpuobj);
+ return -ENOMEM;
+ }
+ gpuobj->im_pramin->start = p_offset;
+ gpuobj->im_pramin->size = size;
+ }
+
+ if (b_offset != ~0) {
+ gpuobj->im_backing = drm_calloc(1, sizeof(struct mem_block),
+ DRM_MEM_DRIVER);
+ if (!gpuobj->im_backing) {
+ nouveau_gpuobj_del(dev, &gpuobj);
+ return -ENOMEM;
+ }
+ gpuobj->im_backing->start = b_offset;
+ gpuobj->im_backing->size = size;
}
- gpuobj->im_pramin->start = offset;
- gpuobj->im_pramin->size = size;
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
@@ -524,7 +587,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size,
}
if (pref) {
- if ((i = nouveau_gpuobj_ref_add(dev, -1, 0, gpuobj, pref))) {
+ if ((i = nouveau_gpuobj_ref_add(dev, NULL, 0, gpuobj, pref))) {
nouveau_gpuobj_del(dev, &gpuobj);
return i;
}
@@ -577,10 +640,11 @@ nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class)
to it that can be used to set up context objects.
*/
int
-nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class,
- uint64_t offset, uint64_t size, int access, int target,
- struct nouveau_gpuobj **gpuobj)
+nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
+ uint64_t offset, uint64_t size, int access,
+ int target, struct nouveau_gpuobj **gpuobj)
{
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
int ret;
uint32_t is_scatter_gather = 0;
@@ -591,7 +655,7 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class,
DRM_DEBUG("ch%d class=0x%04x offset=0x%llx size=0x%llx\n",
- channel, class, offset, size);
+ chan->id, class, offset, size);
DRM_DEBUG("access=%d target=%d\n", access, target);
switch (target) {
@@ -608,7 +672,7 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class,
break;
}
- ret = nouveau_gpuobj_new(dev, channel,
+ ret = nouveau_gpuobj_new(dev, chan,
is_scatter_gather ? ((page_count << 2) + 12) : nouveau_gpuobj_class_instmem_size(dev, class),
16,
NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
@@ -711,19 +775,19 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class,
}
int
-nouveau_gpuobj_gart_dma_new(struct drm_device *dev, int channel,
+nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan,
uint64_t offset, uint64_t size, int access,
struct nouveau_gpuobj **gpuobj,
uint32_t *o_ret)
{
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
int ret;
if (dev_priv->gart_info.type == NOUVEAU_GART_AGP ||
(dev_priv->card_type >= NV_50 &&
dev_priv->gart_info.type == NOUVEAU_GART_SGDMA)) {
- ret = nouveau_gpuobj_dma_new(dev, channel,
- NV_CLASS_DMA_IN_MEMORY,
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
offset, size, access,
NV_DMA_TARGET_AGP, gpuobj);
if (o_ret)
@@ -798,15 +862,16 @@ nouveau_gpuobj_gart_dma_new(struct drm_device *dev, int channel,
set to 0?
*/
int
-nouveau_gpuobj_gr_new(struct drm_device *dev, int channel, int class,
+nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
struct nouveau_gpuobj **gpuobj)
{
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
int ret;
- DRM_DEBUG("ch%d class=0x%04x\n", channel, class);
+ DRM_DEBUG("ch%d class=0x%04x\n", chan->id, class);
- ret = nouveau_gpuobj_new(dev, channel,
+ ret = nouveau_gpuobj_new(dev, chan,
nouveau_gpuobj_class_instmem_size(dev, class),
16,
NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
@@ -847,14 +912,14 @@ nouveau_gpuobj_gr_new(struct drm_device *dev, int channel, int class,
}
static int
-nouveau_gpuobj_channel_init_pramin(struct drm_device *dev, int channel)
+nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
{
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo *chan = dev_priv->fifos[channel];
struct nouveau_gpuobj *pramin = NULL;
int size, base, ret;
- DRM_DEBUG("ch%d\n", channel);
+ DRM_DEBUG("ch%d\n", chan->id);
/* Base amount for object storage (4KiB enough?) */
size = 0x1000;
@@ -876,8 +941,8 @@ nouveau_gpuobj_channel_init_pramin(struct drm_device *dev, int channel)
}
DRM_DEBUG("ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n",
- channel, size, base);
- ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, size, 0x1000, 0,
+ chan->id, size, base);
+ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
&chan->ramin);
if (ret) {
DRM_ERROR("Error allocating channel PRAMIN: %d\n", ret);
@@ -897,21 +962,23 @@ nouveau_gpuobj_channel_init_pramin(struct drm_device *dev, int channel)
}
int
-nouveau_gpuobj_channel_init(struct drm_device *dev, int channel,
+nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
uint32_t vram_h, uint32_t tt_h)
{
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo *chan = dev_priv->fifos[channel];
struct nouveau_gpuobj *vram = NULL, *tt = NULL;
int ret, i;
- DRM_DEBUG("ch%d vram=0x%08x tt=0x%08x\n", channel, vram_h, tt_h);
+ 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
*XXX: maybe on <NV50 too at some point
*/
if (0 || dev_priv->card_type == NV_50) {
- ret = nouveau_gpuobj_channel_init_pramin(dev, channel);
+ ret = nouveau_gpuobj_channel_init_pramin(chan);
if (ret)
return ret;
}
@@ -922,7 +989,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel,
vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
vm_offset += chan->ramin->gpuobj->im_pramin->start;
- if ((ret = nouveau_gpuobj_new_fake(dev, vm_offset, 0x4000,
+ if ((ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
0, &chan->vm_pd, NULL)))
return ret;
for (i=0; i<0x4000; i+=8) {
@@ -930,7 +997,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel,
INSTANCE_WR(chan->vm_pd, (i+4)/4, 0xdeadcafe);
}
- if ((ret = nouveau_gpuobj_ref_add(dev, -1, 0,
+ if ((ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
dev_priv->gart_info.sg_ctxdma,
&chan->vm_gart_pt)))
return ret;
@@ -941,12 +1008,12 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel,
/* RAMHT */
if (dev_priv->card_type < NV_50) {
- ret = nouveau_gpuobj_ref_add(dev, -1, 0, dev_priv->ramht,
+ ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->ramht,
&chan->ramht);
if (ret)
return ret;
} else {
- ret = nouveau_gpuobj_new_ref(dev, channel, channel, 0,
+ ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0,
0x8000, 16,
NVOBJ_FLAG_ZERO_ALLOC,
&chan->ramht);
@@ -955,7 +1022,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel,
}
/* VRAM ctxdma */
- if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY,
+ if ((ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
0, dev_priv->fb_available_size,
NV_DMA_ACCESS_RW,
NV_DMA_TARGET_VIDMEM, &vram))) {
@@ -963,20 +1030,19 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel,
return ret;
}
- if ((ret = nouveau_gpuobj_ref_add(dev, channel, vram_h, vram, NULL))) {
+ if ((ret = nouveau_gpuobj_ref_add(dev, chan, vram_h, vram, NULL))) {
DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret);
return ret;
}
/* TT memory ctxdma */
if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
- ret = nouveau_gpuobj_gart_dma_new(dev, channel, 0,
+ ret = nouveau_gpuobj_gart_dma_new(chan, 0,
dev_priv->gart_info.aper_size,
NV_DMA_ACCESS_RW, &tt, NULL);
} else
if (dev_priv->pci_heap) {
- ret = nouveau_gpuobj_dma_new(dev, channel,
- NV_CLASS_DMA_IN_MEMORY,
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
0, dev->sg->pages * PAGE_SIZE,
NV_DMA_ACCESS_RW,
NV_DMA_TARGET_PCI_NONLINEAR, &tt);
@@ -990,7 +1056,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel,
return ret;
}
- ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL);
+ ret = nouveau_gpuobj_ref_add(dev, chan, tt_h, tt, NULL);
if (ret) {
DRM_ERROR("Error referencing TT ctxdma: %d\n", ret);
return ret;
@@ -1000,18 +1066,20 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel,
}
void
-nouveau_gpuobj_channel_takedown(struct drm_device *dev, int channel)
+nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ struct drm_device *dev = chan->dev;
+ struct list_head *entry, *tmp;
struct nouveau_gpuobj_ref *ref;
- DRM_DEBUG("ch%d\n", channel);
+ DRM_DEBUG("ch%d\n", chan->id);
+
+ list_for_each_safe(entry, tmp, &chan->ramht_refs) {
+ ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
- while ((ref = chan->ramht_refs)) {
- chan->ramht_refs = ref->next;
nouveau_gpuobj_ref_del(dev, &ref);
}
+
nouveau_gpuobj_ref_del(dev, &chan->ramht);
nouveau_gpuobj_del(dev, &chan->vm_pd);
@@ -1024,35 +1092,33 @@ nouveau_gpuobj_channel_takedown(struct drm_device *dev, int channel)
}
-int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
+ struct nouveau_channel *chan;
struct drm_nouveau_grobj_alloc *init = data;
struct nouveau_gpuobj *gr = NULL;
int ret;
- if (!nouveau_fifo_owner(dev, file_priv, init->channel)) {
- DRM_ERROR("pid %d doesn't own channel %d\n",
- DRM_CURRENTPID, init->channel);
- return -EINVAL;
- }
+ 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
if (init->handle == ~0)
return -EINVAL;
- if (nouveau_gpuobj_ref_find(dev, init->channel, init->handle, NULL) ==
- 0)
+
+ if (nouveau_gpuobj_ref_find(chan, init->handle, NULL) == 0)
return -EEXIST;
- ret = nouveau_gpuobj_gr_new(dev, init->channel, init->class, &gr);
+ ret = nouveau_gpuobj_gr_new(chan, init->class, &gr);
if (ret) {
DRM_ERROR("Error creating gr object: %d (%d/0x%08x)\n",
ret, init->channel, init->handle);
return ret;
}
- if ((ret = nouveau_gpuobj_ref_add(dev, init->channel, init->handle,
- gr, NULL))) {
+ if ((ret = nouveau_gpuobj_ref_add(dev, chan, init->handle, gr, NULL))) {
DRM_ERROR("Error referencing gr object: %d (%d/0x%08x\n)",
ret, init->channel, init->handle);
nouveau_gpuobj_del(dev, &gr);
@@ -1062,3 +1128,21 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct drm_fil
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;
+}
+