From 695599f18d907bb277805581bbe208b0e083e7d9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 19:03:35 +1000 Subject: nouveau: Nuke DMA_OBJECT_INIT ioctl (bumps interface to 0.0.7) For various reasons, this ioctl was a bad idea. At channel creation we now automatically create DMA objects covering available VRAM and GART memory, where the client used to do this themselves. However, there is still a need to be able to create DMA objects pointing at specific areas of memory (ie. notifiers). Each channel is now allocated a small amount of memory from which a client can suballocate things (such as notifiers), and have a DMA object created which covers the suballocated area. The NOTIFIER_ALLOC ioctl exposes this functionality. --- shared-core/nouveau_object.c | 143 ++++++++++++++----------------------------- 1 file changed, 47 insertions(+), 96 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index e36568c6..e7528e23 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -153,13 +153,13 @@ nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle) return hash << 3; } -static int +int nouveau_ht_object_insert(drm_device_t* dev, int channel, uint32_t handle, struct nouveau_object *obj) { drm_nouveau_private_t *dev_priv=dev->dev_private; int ht_base = NV_RAMIN + dev_priv->ramht_offset; - int ht_end = ht_base + dev_priv->ramht_size; +/* int ht_end = ht_base + dev_priv->ramht_size; */ int o_ofs, ofs; obj->handle = handle; @@ -461,115 +461,70 @@ nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj) drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER); } -void nouveau_object_cleanup(drm_device_t *dev, int channel) -{ - drm_nouveau_private_t *dev_priv=dev->dev_private; - - while (dev_priv->fifos[channel].objs) { - nouveau_object_free(dev, dev_priv->fifos[channel].objs); - } -} - -int nouveau_ioctl_object_init(DRM_IOCTL_ARGS) +int +nouveau_object_init_channel(drm_device_t *dev, int channel, + uint32_t vram_handle, + uint32_t tt_handle) { - DRM_DEVICE; - drm_nouveau_object_init_t init; - struct nouveau_object *obj; - - DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_object_init_t __user *) - data, sizeof(init)); - - if (!nouveau_fifo_owner(dev, filp, init.channel)) { - DRM_ERROR("pid %d doesn't own channel %d\n", - DRM_CURRENTPID, init.channel); - return DRM_ERR(EINVAL); + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_object *gpuobj; + int ret; + + /* VRAM ctxdma */ + gpuobj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->fb_available_size, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_VIDMEM); + if (!gpuobj) { + DRM_ERROR("Error creating VRAM ctxdma: %d\n", DRM_ERR(ENOMEM)); + return DRM_ERR(ENOMEM); } - //FIXME: check args, only allow trusted objects to be created - - if (nouveau_object_handle_find(dev, init.channel, init.handle)) { - DRM_ERROR("Channel %d: handle 0x%08x already exists\n", - init.channel, init.handle); - return DRM_ERR(EINVAL); + ret = nouveau_ht_object_insert(dev, channel, vram_handle, gpuobj); + if (ret) { + DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret); + return ret; } - obj = nouveau_object_gr_create(dev, init.channel, init.class); - if (!obj) + /* non-AGP unimplemented */ + if (dev_priv->agp_heap == NULL) + return 0; + + /* GART ctxdma */ + gpuobj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->agp_available_size, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_AGP); + if (!gpuobj) { + DRM_ERROR("Error creating TT ctxdma: %d\n", DRM_ERR(ENOMEM)); return DRM_ERR(ENOMEM); + } - if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) { - nouveau_object_free(dev, obj); - return DRM_ERR(ENOMEM); + ret = nouveau_ht_object_insert(dev, channel, tt_handle, gpuobj); + if (ret) { + DRM_ERROR("Error referencing TT ctxdma: %d\n", ret); + return ret; } return 0; } -static int -nouveau_dma_object_check_access(drm_device_t *dev, - drm_nouveau_dma_object_init_t *init) +void nouveau_object_cleanup(drm_device_t *dev, int channel) { - drm_nouveau_private_t *dev_priv = dev->dev_private; - uint64_t limit; - - /* Check for known DMA object classes */ - switch (init->class) { - case NV_CLASS_DMA_IN_MEMORY: - case NV_CLASS_DMA_FROM_MEMORY: - case NV_CLASS_DMA_TO_MEMORY: - break; - default: - DRM_ERROR("invalid class = 0x%x\n", init->class); - return DRM_ERR(EPERM); - } - - /* Check access mode, and translate to NV_DMA_ACCESS_* */ - switch (init->access) { - case NOUVEAU_MEM_ACCESS_RO: - init->access = NV_DMA_ACCESS_RO; - break; - case NOUVEAU_MEM_ACCESS_WO: - init->access = NV_DMA_ACCESS_WO; - break; - case NOUVEAU_MEM_ACCESS_RW: - init->access = NV_DMA_ACCESS_RW; - break; - default: - DRM_ERROR("invalid access mode = %d\n", init->access); - return DRM_ERR(EPERM); - } - - /* Check that request is within the allowed limits of "target" */ - switch (init->target) { - case NOUVEAU_MEM_FB: - limit = dev_priv->fb_available_size; - init->target = NV_DMA_TARGET_VIDMEM; - break; - case NOUVEAU_MEM_AGP: - limit = dev_priv->agp_available_size; - init->target = NV_DMA_TARGET_AGP; - break; - default: - DRM_ERROR("invalid target = 0x%x\n", init->target); - return DRM_ERR(EPERM); - } + drm_nouveau_private_t *dev_priv=dev->dev_private; - if ((init->offset > limit) || (init->offset + init->size) > limit) { - DRM_ERROR("access out of allowed range (%d,0x%08x,0x%08x)\n", - init->target, init->offset, init->size); - return DRM_ERR(EPERM); + while (dev_priv->fifos[channel].objs) { + nouveau_object_free(dev, dev_priv->fifos[channel].objs); } - - return 0; } -int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS) +int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) { DRM_DEVICE; - drm_nouveau_dma_object_init_t init; + drm_nouveau_grobj_alloc_t init; struct nouveau_object *obj; - DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_dma_object_init_t __user *) + DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_grobj_alloc_t __user *) data, sizeof(init)); if (!nouveau_fifo_owner(dev, filp, init.channel)) { @@ -578,8 +533,7 @@ int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - if (nouveau_dma_object_check_access(dev, &init)) - return DRM_ERR(EPERM); + //FIXME: check args, only allow trusted objects to be created if (nouveau_object_handle_find(dev, init.channel, init.handle)) { DRM_ERROR("Channel %d: handle 0x%08x already exists\n", @@ -587,13 +541,10 @@ int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - obj = nouveau_object_dma_create(dev, init.channel, init.class, - init.offset, init.size, - init.access, init.target); + obj = nouveau_object_gr_create(dev, init.channel, init.class); if (!obj) return DRM_ERR(ENOMEM); - obj->handle = init.handle; if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) { nouveau_object_free(dev, obj); return DRM_ERR(ENOMEM); -- cgit v1.2.3 From 68ecf61647e9ec16d59cc8f50550d11478eb3118 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 25 Jun 2007 15:42:55 +1000 Subject: nouveau: never touch PRAMIN with NV_WRITE, cleanup RAMHT code a bit --- shared-core/nouveau_object.c | 133 ++++++++++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 53 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index e7528e23..dac08df4 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -139,7 +139,7 @@ nouveau_object_handle_find(drm_device_t *dev, int channel, uint32_t handle) is given as: */ static uint32_t -nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle) +nouveau_ramht_hash_handle(drm_device_t *dev, int channel, uint32_t handle) { drm_nouveau_private_t *dev_priv=dev->dev_private; uint32_t hash = 0; @@ -153,63 +153,90 @@ nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle) return hash << 3; } +static int +nouveau_ramht_entry_valid(drm_device_t *dev, uint32_t ramht, uint32_t offset) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + uint32_t ctx = NV_RI32(ramht + offset + 4); + + if (dev_priv->card_type < NV_40) + return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0); + return (ctx != 0); +} + int -nouveau_ht_object_insert(drm_device_t* dev, int channel, uint32_t handle, - struct nouveau_object *obj) +nouveau_ramht_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 o_ofs, ofs; - - obj->handle = handle; - o_ofs = ofs = nouveau_ht_handle_hash(dev, channel, obj->handle); - - while (NV_READ(ht_base + ofs) || NV_READ(ht_base + ofs + 4)) { - ofs += 8; - if (ofs == dev_priv->ramht_size) ofs = 0; - if (ofs == o_ofs) { - DRM_ERROR("no free hash table entries\n"); - return 1; - } + uint32_t ramht = dev_priv->ramht_offset; + uint32_t ctx, co, ho; + uint32_t inst; + + inst = nouveau_chip_instance_get(dev, obj->instance); + if (dev_priv->card_type < NV_40) { + ctx = NV_RAMHT_CONTEXT_VALID | inst | + (channel << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | + (obj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); + } else + if (dev_priv->card_type < NV_50) { + ctx = inst | + (channel << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | + (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); + } else { + ctx = inst | + (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); } - ofs += ht_base; - - DRM_DEBUG("Channel %d - Handle 0x%08x at 0x%08x\n", - channel, obj->handle, ofs); - - NV_WRITE(NV_RAMHT_HANDLE_OFFSET + ofs, obj->handle); - if (dev_priv->card_type >= NV_40) - NV_WRITE(NV_RAMHT_CONTEXT_OFFSET + ofs, - (channel << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | - (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT) | - nouveau_chip_instance_get(dev, obj->instance) - ); - else - NV_WRITE(NV_RAMHT_CONTEXT_OFFSET + ofs, - NV_RAMHT_CONTEXT_VALID | - (channel << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | - (obj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT) | - nouveau_chip_instance_get(dev, obj->instance) - ); - - obj->ht_loc = ofs; - return 0; + + co = ho = nouveau_ramht_hash_handle(dev, channel, handle); + do { + if (!nouveau_ramht_entry_valid(dev, ramht, co)) { + DRM_DEBUG("insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n", + channel, co, handle, ctx); + NV_WI32(ramht + co + 0, handle); + NV_WI32(ramht + co + 4, ctx); + obj->handle = handle; + return 0; + } + DRM_DEBUG("collision ch%d 0x%08x: h=0x%08x\n", + channel, co, NV_RI32(ramht + co)); + + co += 8; + if (co == dev_priv->ramht_size) + co = 0; + } while (co != ho); + + DRM_ERROR("RAMHT space exhausted. ch=%d\n", channel); + return DRM_ERR(ENOMEM); } -static void nouveau_hash_table_remove(drm_device_t* dev, - struct nouveau_object *obj) +static void +nouveau_ramht_remove(drm_device_t* dev, struct nouveau_object *obj) { drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t ramht = dev_priv->ramht_offset; + uint32_t co, ho; + + co = ho = nouveau_ramht_hash_handle(dev, obj->channel, obj->handle); + do { + if (nouveau_ramht_entry_valid(dev, ramht, co) && + (obj->handle == NV_RI32(ramht + co))) { + DRM_DEBUG("remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n", + obj->channel, co, obj->handle, + NV_RI32(ramht + co + 4)); + NV_WI32(ramht + co + 0, 0x00000000); + NV_WI32(ramht + co + 4, 0x00000000); + obj->handle = ~0; + return; + } - DRM_DEBUG("Remove handle 0x%08x at 0x%08x from HT\n", - obj->handle, obj->ht_loc); - if (obj->ht_loc) { - DRM_DEBUG("... HT entry was: 0x%08x/0x%08x\n", - NV_READ(obj->ht_loc), NV_READ(obj->ht_loc+4)); - NV_WRITE(obj->ht_loc , 0x00000000); - NV_WRITE(obj->ht_loc+4, 0x00000000); - } + co += 8; + if (co == dev_priv->ramht_size) + co = 0; + } while (co != ho); + + DRM_ERROR("RAMHT entry not found. ch=%d, handle=0x%08x\n", + obj->channel, obj->handle); } static struct nouveau_object * @@ -457,7 +484,7 @@ nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj) { nouveau_object_instance_free(dev, obj); if (obj->handle != ~0) - nouveau_hash_table_remove(dev, obj); + nouveau_ramht_remove(dev, obj); drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER); } @@ -480,7 +507,7 @@ nouveau_object_init_channel(drm_device_t *dev, int channel, return DRM_ERR(ENOMEM); } - ret = nouveau_ht_object_insert(dev, channel, vram_handle, gpuobj); + ret = nouveau_ramht_insert(dev, channel, vram_handle, gpuobj); if (ret) { DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret); return ret; @@ -500,7 +527,7 @@ nouveau_object_init_channel(drm_device_t *dev, int channel, return DRM_ERR(ENOMEM); } - ret = nouveau_ht_object_insert(dev, channel, tt_handle, gpuobj); + ret = nouveau_ramht_insert(dev, channel, tt_handle, gpuobj); if (ret) { DRM_ERROR("Error referencing TT ctxdma: %d\n", ret); return ret; @@ -545,7 +572,7 @@ int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) if (!obj) return DRM_ERR(ENOMEM); - if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) { + if (nouveau_ramht_insert(dev, init.channel, init.handle, obj)) { nouveau_object_free(dev, obj); return DRM_ERR(ENOMEM); } -- cgit v1.2.3 From 163f8526123ffa38783fc911b5f7a19debce7f73 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 2 Jul 2007 19:31:18 +1000 Subject: nouveau: rewrite gpu object code Allows multiple references to a single object, needed to support PCI(E)GART scatter-gather DMA objects which would quickly fill PRAMIN if each channel had its own. Handle per-channel private instmem areas. This is needed to support NV50, but might be something we want to do on earlier chipsets at some point? Everything that touches PRAMIN is a GPU object. --- shared-core/nouveau_object.c | 827 +++++++++++++++++++++++++++++-------------- 1 file changed, 559 insertions(+), 268 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index dac08df4..79875ca1 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -35,79 +35,6 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" -/* TODO - * - Check object class, deny unsafe objects (add card-specific versioning?) - * - Get rid of DMA object creation, this should be wrapped by MM routines. - */ - -/* Translate a RAMIN offset into a value the card understands, will be useful - * in the future when we can access more instance ram which isn't mapped into - * the PRAMIN aperture - */ -uint32_t -nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem) -{ - uint32_t inst = (uint32_t)mem->start >> 4; - DRM_DEBUG("****** on-chip instance for 0x%016llx = 0x%08x\n", - mem->start, inst); - return inst; -} - -static void -nouveau_object_link(drm_device_t *dev, struct nouveau_object *obj) -{ - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[obj->channel]; - - if (!chan->objs) { - chan->objs = obj; - return; - } - - obj->prev = NULL; - obj->next = chan->objs; - - chan->objs->prev = obj; - chan->objs = obj; -} - -static void -nouveau_object_unlink(drm_device_t *dev, struct nouveau_object *obj) -{ - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[obj->channel]; - - if (obj->prev == NULL) { - if (obj->next) - obj->next->prev = NULL; - chan->objs = obj->next; - } else if (obj->next == NULL) { - if (obj->prev) - obj->prev->next = NULL; - } else { - obj->prev->next = obj->next; - obj->next->prev = obj->prev; - } -} - -static struct nouveau_object * -nouveau_object_handle_find(drm_device_t *dev, int channel, uint32_t handle) -{ - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - struct nouveau_object *obj = chan->objs; - - DRM_DEBUG("Looking for handle 0x%08x\n", handle); - while (obj) { - if (obj->handle == handle) - return obj; - obj = obj->next; - } - - DRM_DEBUG("...couldn't find handle\n"); - return NULL; -} - /* NVidia uses context objects to drive drawing operations. Context objects can be selected into 8 subchannels in the FIFO, @@ -150,146 +77,439 @@ nouveau_ramht_hash_handle(drm_device_t *dev, int channel, uint32_t handle) handle >>= dev_priv->ramht_bits; } hash ^= channel << (dev_priv->ramht_bits - 4); - return hash << 3; + hash <<= 3; + + DRM_DEBUG("ch%d handle=0x%08x hash=0x%08x\n", channel, handle, hash); + return hash; } static int -nouveau_ramht_entry_valid(drm_device_t *dev, uint32_t ramht, uint32_t offset) +nouveau_ramht_entry_valid(drm_device_t *dev, nouveau_gpuobj_t *ramht, + uint32_t offset) { drm_nouveau_private_t *dev_priv=dev->dev_private; - uint32_t ctx = NV_RI32(ramht + offset + 4); + uint32_t ctx = INSTANCE_RD(ramht, (offset + 4)/4); if (dev_priv->card_type < NV_40) return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0); return (ctx != 0); } -int -nouveau_ramht_insert(drm_device_t* dev, int channel, uint32_t handle, - struct nouveau_object *obj) +static int +nouveau_ramht_insert(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) { drm_nouveau_private_t *dev_priv=dev->dev_private; - uint32_t ramht = dev_priv->ramht_offset; + struct nouveau_fifo *chan = &dev_priv->fifos[ref->channel]; + nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; + nouveau_gpuobj_t *gpuobj = ref->gpuobj; uint32_t ctx, co, ho; - uint32_t inst; - inst = nouveau_chip_instance_get(dev, obj->instance); + if (!ramht) { + DRM_ERROR("No hash table!\n"); + return DRM_ERR(EINVAL); + } + if (dev_priv->card_type < NV_40) { - ctx = NV_RAMHT_CONTEXT_VALID | inst | - (channel << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | - (obj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); + ctx = NV_RAMHT_CONTEXT_VALID | (ref->instance >> 4) | + (ref->channel << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | + (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); } else if (dev_priv->card_type < NV_50) { - ctx = inst | - (channel << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | - (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); + ctx = (ref->instance >> 4) | + (ref->channel << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | + (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); } else { - ctx = inst | - (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); + ctx = (ref->instance >> 4) | + (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); } - co = ho = nouveau_ramht_hash_handle(dev, channel, handle); + co = ho = nouveau_ramht_hash_handle(dev, ref->channel, ref->handle); do { if (!nouveau_ramht_entry_valid(dev, ramht, co)) { DRM_DEBUG("insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n", - channel, co, handle, ctx); - NV_WI32(ramht + co + 0, handle); - NV_WI32(ramht + co + 4, ctx); - obj->handle = handle; + ref->channel, co, ref->handle, ctx); + INSTANCE_WR(ramht, (co + 0)/4, ref->handle); + INSTANCE_WR(ramht, (co + 4)/4, ctx); return 0; } DRM_DEBUG("collision ch%d 0x%08x: h=0x%08x\n", - channel, co, NV_RI32(ramht + co)); + ref->channel, co, INSTANCE_RD(ramht, co/4)); co += 8; - if (co == dev_priv->ramht_size) + if (co >= dev_priv->ramht_size) co = 0; } while (co != ho); - DRM_ERROR("RAMHT space exhausted. ch=%d\n", channel); + DRM_ERROR("RAMHT space exhausted. ch=%d\n", ref->channel); return DRM_ERR(ENOMEM); } static void -nouveau_ramht_remove(drm_device_t* dev, struct nouveau_object *obj) +nouveau_ramht_remove(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t ramht = dev_priv->ramht_offset; + struct nouveau_fifo *chan = &dev_priv->fifos[ref->channel]; + nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; uint32_t co, ho; - co = ho = nouveau_ramht_hash_handle(dev, obj->channel, obj->handle); + if (!ramht) { + DRM_ERROR("No hash table!\n"); + return; + } + + co = ho = nouveau_ramht_hash_handle(dev, ref->channel, ref->handle); do { if (nouveau_ramht_entry_valid(dev, ramht, co) && - (obj->handle == NV_RI32(ramht + co))) { + (ref->handle == INSTANCE_RD(ramht, (co/4)))) { DRM_DEBUG("remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n", - obj->channel, co, obj->handle, - NV_RI32(ramht + co + 4)); - NV_WI32(ramht + co + 0, 0x00000000); - NV_WI32(ramht + co + 4, 0x00000000); - obj->handle = ~0; + ref->channel, co, ref->handle, + INSTANCE_RD(ramht, (co + 4))); + INSTANCE_WR(ramht, (co + 0)/4, 0x00000000); + INSTANCE_WR(ramht, (co + 4)/4, 0x00000000); return; } co += 8; - if (co == dev_priv->ramht_size) + if (co >= dev_priv->ramht_size) co = 0; } while (co != ho); DRM_ERROR("RAMHT entry not found. ch=%d, handle=0x%08x\n", - obj->channel, obj->handle); + ref->channel, ref->handle); } -static struct nouveau_object * -nouveau_object_instance_alloc(drm_device_t* dev, int channel) +int +nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, + uint32_t flags, nouveau_gpuobj_t **gpuobj_ret) { - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_object *obj; + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = NULL; + nouveau_gpuobj_t *gpuobj; + struct mem_block *pramin = NULL; + + DRM_DEBUG("ch%d size=%d align=%d flags=0x%08x\n", + channel, size, align, flags); - /* Create object struct */ - obj = drm_calloc(1, sizeof(struct nouveau_object), DRM_MEM_DRIVER); - if (!obj) { - DRM_ERROR("couldn't alloc memory for object\n"); - return NULL; + if (!dev_priv || !gpuobj_ret || *gpuobj_ret != NULL) + return DRM_ERR(EINVAL); + + if (channel >= 0) { + if (channel > nouveau_fifo_number(dev)) + return DRM_ERR(EINVAL); + chan = &dev_priv->fifos[channel]; } - /* Allocate instance memory */ - obj->instance = nouveau_instmem_alloc(dev, - (dev_priv->card_type >= NV_40 ? 32 : 16), 4); - if (!obj->instance) { - DRM_ERROR("couldn't alloc RAMIN for object\n"); - drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER); - return NULL; + gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER); + if (!gpuobj) + return DRM_ERR(ENOMEM); + DRM_DEBUG("gpuobj %p\n", gpuobj); + gpuobj->flags = flags; + gpuobj->im_channel = channel; + + /* Choose between global instmem heap, and per-channel private + * instmem heap. On ramin_heap) { + DRM_DEBUG("private heap\n"); + pramin = chan->ramin_heap; + } else + if (dev_priv->card_type < NV_50) { + DRM_DEBUG("global heap fallback\n"); + pramin = dev_priv->ramin_heap; + } + } else { + DRM_DEBUG("global heap\n"); + pramin = dev_priv->ramin_heap; + } + + if (!pramin) { + DRM_ERROR("No PRAMIN heap!\n"); + return DRM_ERR(EINVAL); } - /* Bind object to channel */ - obj->channel = channel; - obj->handle = ~0; - nouveau_object_link(dev, obj); + /* Allocate a chunk of the PRAMIN aperture */ + gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size, + drm_order(align), + (DRMFILE)-2); + if (!gpuobj->im_pramin) { + nouveau_gpuobj_del(dev, &gpuobj); + return DRM_ERR(ENOMEM); + } + gpuobj->im_pramin->flags = NOUVEAU_MEM_INSTANCE; + + /* On NV50 the PRAMIN aperture is paged. When allocating from the + * global instmem heap, alloc and bind VRAM pages into the PRAMIN + * aperture. + */ + if (!chan && dev_priv->card_type >= NV_50) { + DRM_ERROR("back aperture with vram pages\n"); + nouveau_gpuobj_del(dev, &gpuobj); + return DRM_ERR(EINVAL); + } - return obj; + if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { + int i; + + for (i = 0; i < gpuobj->im_pramin->size; i += 4) + INSTANCE_WR(gpuobj, i/4, 0); + } + + if (dev_priv->gpuobj_all) { + gpuobj->next = dev_priv->gpuobj_all; + gpuobj->next->prev = gpuobj; + } + dev_priv->gpuobj_all = gpuobj; + + *gpuobj_ret = gpuobj; + return 0; } -static void -nouveau_object_instance_free(drm_device_t *dev, struct nouveau_object *obj) +void nouveau_gpuobj_takedown(drm_device_t *dev) { - drm_nouveau_private_t *dev_priv=dev->dev_private; + drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_gpuobj_t *gpuobj = NULL; + + DRM_DEBUG("\n"); + + while ((gpuobj = dev_priv->gpuobj_all)) { + DRM_ERROR("gpuobj %p still exists at takedown, refs=%d\n", + gpuobj, gpuobj->refcount); + gpuobj->refcount = 0; + nouveau_gpuobj_del(dev, &gpuobj); + } +} + +int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_gpuobj_t *gpuobj; + + DRM_DEBUG("gpuobj %p\n", pgpuobj ? *pgpuobj : NULL); + + if (!dev_priv || !pgpuobj || !(*pgpuobj)) + return DRM_ERR(EINVAL); + gpuobj = *pgpuobj; + + if (gpuobj->refcount != 0) { + DRM_ERROR("gpuobj refcount is %d\n", gpuobj->refcount); + return DRM_ERR(EINVAL); + } + + if (gpuobj->im_pramin) { + if (gpuobj->flags & NVOBJ_FLAG_FAKE) + drm_free(gpuobj->im_pramin, sizeof(*gpuobj->im_pramin), + DRM_MEM_DRIVER); + else + nouveau_mem_free_block(gpuobj->im_pramin); + } + + if (gpuobj->im_backing) + nouveau_mem_free(dev, gpuobj->im_backing); + + if (gpuobj->next) + gpuobj->next->prev = gpuobj->prev; + if (gpuobj->prev) + gpuobj->prev->next = gpuobj->next; + else + dev_priv->gpuobj_all = gpuobj->next; + + *pgpuobj = NULL; + drm_free(gpuobj, sizeof(*gpuobj), DRM_MEM_DRIVER); + return 0; +} + +static int +nouveau_gpuobj_instance_get(drm_device_t *dev, int channel, + nouveau_gpuobj_t *gpuobj, uint32_t *inst) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_gpuobj_t *cpramin; + + if ((channel > 0) && gpuobj->im_channel != channel) { + DRM_ERROR("Channel mismatch: obj %d, ref %d\n", + gpuobj->im_channel, channel); + return DRM_ERR(EINVAL); + } + + /* card_type < NV_50) { + *inst = gpuobj->im_pramin->start; + return 0; + } + + /* NV50 channel-local instance */ + if (channel > 0) { + cpramin = dev_priv->fifos[channel].ramin->gpuobj; + *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start; + return 0; + } + + /* NV50 global (VRAM) instance */ + if (gpuobj->im_channel < 0) { + /* ...from global heap */ + if (!gpuobj->im_backing) { + DRM_ERROR("AII, no VRAM backing gpuobj\n"); + return DRM_ERR(EINVAL); + } + *inst = gpuobj->im_backing->start - dev_priv->fb_phys; + return 0; + } else { + /* ...from local heap */ + cpramin = dev_priv->fifos[gpuobj->im_channel].ramin->gpuobj; + *inst = (cpramin->im_backing->start - dev_priv->fb_phys) + + (gpuobj->im_pramin->start - cpramin->im_pramin->start); + return 0; + } + + return DRM_ERR(EINVAL); +} + +int +nouveau_gpuobj_ref_add(drm_device_t *dev, int channel, uint32_t handle, + nouveau_gpuobj_t *gpuobj, nouveau_gpuobj_ref_t **ref_ret) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = NULL; + nouveau_gpuobj_ref_t *ref; + uint32_t instance; + int ret; + + DRM_DEBUG("ch%d h=0x%08x gpuobj=%p\n", channel, handle, gpuobj); + + if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL)) + return DRM_ERR(EINVAL); + + if (channel >= 0) { + if (channel > nouveau_fifo_number(dev)) + return DRM_ERR(EINVAL); + chan = &dev_priv->fifos[channel]; + } else + if (!ref_ret) + return DRM_ERR(EINVAL); + + ret = nouveau_gpuobj_instance_get(dev, channel, gpuobj, &instance); + if (ret) + return ret; + + ref = drm_calloc(1, sizeof(*ref), DRM_MEM_DRIVER); + if (!ref) + return DRM_ERR(ENOMEM); + ref->gpuobj = gpuobj; + ref->channel = channel; + ref->instance = instance; + + if (!ref_ret) { + ref->handle = handle; + + ret = nouveau_ramht_insert(dev, ref); + if (ret) { + 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; + } + + ref->gpuobj->refcount++; + return 0; +} + +int nouveau_gpuobj_ref_del(drm_device_t *dev, nouveau_gpuobj_ref_t **pref) +{ + nouveau_gpuobj_ref_t *ref; + + DRM_DEBUG("ref %p\n", pref ? *pref : NULL); + + if (!dev || !pref || *pref == NULL) + return DRM_ERR(EINVAL); + ref = *pref; + + if (ref->handle != ~0) + nouveau_ramht_remove(dev, ref); + + if (ref->gpuobj) { + ref->gpuobj->refcount--; + + if (ref->gpuobj->refcount == 0) { + if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS)) + nouveau_gpuobj_del(dev, &ref->gpuobj); + } + } + + *pref = NULL; + drm_free(ref, sizeof(ref), DRM_MEM_DRIVER); + return 0; +} + +int +nouveau_gpuobj_new_ref(drm_device_t *dev, int oc, int rc, uint32_t handle, + int size, int align, uint32_t flags, + nouveau_gpuobj_ref_t **ref) +{ + nouveau_gpuobj_t *gpuobj = NULL; + int ret; + + if ((ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj))) + return ret; + + if ((ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref))) { + nouveau_gpuobj_del(dev, &gpuobj); + return ret; + } + + return 0; +} + +int +nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size, + uint32_t flags, nouveau_gpuobj_t **pgpuobj, + nouveau_gpuobj_ref_t **pref) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_gpuobj_t *gpuobj = NULL; int i; - /* Unbind object from channel */ - nouveau_object_unlink(dev, obj); + DRM_DEBUG("offset=0x%08x size=0x%08x flags=0x%08x\n", + offset, size, flags); + + gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER); + if (!gpuobj) + return DRM_ERR(ENOMEM); + DRM_DEBUG("gpuobj %p\n", gpuobj); + 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 DRM_ERR(ENOMEM); + } + 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) + INSTANCE_WR(gpuobj, i/4, 0); + } - /* Clean RAMIN entry */ - DRM_DEBUG("Instance entry for 0x%08x" - "(engine %d, class 0x%x) before destroy:\n", - obj->handle, obj->engine, obj->class); - for (i=0; i<(obj->instance->size/4); i++) { - DRM_DEBUG(" +0x%02x: 0x%08x\n", (i*4), - INSTANCE_RD(obj->instance, i)); - INSTANCE_WR(obj->instance, i, 0x00000000); + if (pref) { + if ((i = nouveau_gpuobj_ref_add(dev, -1, 0, gpuobj, pref))) { + nouveau_gpuobj_del(dev, &gpuobj); + return i; + } } - /* Free RAMIN */ - nouveau_instmem_free(dev, obj->instance); + if (pgpuobj) + *pgpuobj = gpuobj; + return 0; } /* @@ -317,64 +537,70 @@ nouveau_object_instance_free(drm_device_t *dev, struct nouveau_object *obj) to it that can be used to set up context objects. */ -struct nouveau_object * -nouveau_object_dma_create(drm_device_t* dev, int channel, int class, - uint32_t offset, uint32_t size, - int access, int target) +static int +nouveau_gpuobj_class_instmem_size(drm_device_t *dev, int class) { - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_object *obj; - uint32_t frame, adjust; - uint32_t pte_flags = 0; - - DRM_DEBUG("offset:0x%08x, size:0x%08x, target:%d, access:%d\n", - offset, size, target, access); + drm_nouveau_private_t *dev_priv = dev->dev_private; - switch (target) { - case NV_DMA_TARGET_AGP: - offset += dev_priv->agp_phys; - break; - default: - break; - } + /*XXX: dodgy hack for now */ + if (dev_priv->card_type >= NV_50) + return 24; + if (dev_priv->card_type >= NV_40) + return 32; + return 16; +} - switch (access) { - case NV_DMA_ACCESS_RO: - break; - case NV_DMA_ACCESS_WO: - case NV_DMA_ACCESS_RW: - pte_flags |= (1 << 1); - break; - default: - DRM_ERROR("invalid access mode=%d\n", access); - return NULL; - } +int +nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, + uint64_t offset, uint64_t size, int access, int target, + nouveau_gpuobj_t **gpuobj) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + int ret; - frame = offset & ~0x00000FFF; - adjust = offset & 0x00000FFF; + DRM_DEBUG("ch%d class=0x%04x offset=0x%llx size=0x%llx\n", + channel, class, offset, size); + DRM_DEBUG("access=%d target=%d\n", access, target); - obj = nouveau_object_instance_alloc(dev, channel); - if (!obj) { - DRM_ERROR("couldn't allocate DMA object\n"); - return obj; + ret = nouveau_gpuobj_new(dev, channel, + nouveau_gpuobj_class_instmem_size(dev, class), + 16, + NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, + gpuobj); + if (ret) { + DRM_ERROR("Error creating gpuobj: %d\n", ret); + return ret; } - obj->engine = 0; - obj->class = class; - - INSTANCE_WR(obj->instance, 0, ((1<<12) | (1<<13) | - (adjust << 20) | - (access << 14) | - (target << 16) | - class)); - INSTANCE_WR(obj->instance, 1, size-1); - INSTANCE_WR(obj->instance, 2, frame | pte_flags); - INSTANCE_WR(obj->instance, 3, frame | pte_flags); + if (dev_priv->card_type < NV_50) { + uint32_t frame, adjust, pte_flags = 0; + + if (target == NV_DMA_TARGET_AGP) + offset += dev_priv->agp_phys; + if (access != NV_DMA_ACCESS_RO) + pte_flags |= (1<<1); + frame = offset & ~0x00000fff; + adjust = offset & 0x00000fff; + + INSTANCE_WR(*gpuobj, 0, ((1<<12) | (1<<13) | + (adjust << 20) | + (access << 14) | + (target << 16) | + class)); + INSTANCE_WR(*gpuobj, 1, size - 1); + INSTANCE_WR(*gpuobj, 2, frame | pte_flags); + INSTANCE_WR(*gpuobj, 3, frame | pte_flags); + } else { + nouveau_gpuobj_del(dev, gpuobj); + DRM_ERROR("stub\n"); + return DRM_ERR(EINVAL); + } - return obj; + (*gpuobj)->engine = NVOBJ_ENGINE_SW; + (*gpuobj)->class = class; + return 0; } - /* Context objects in the instance RAM have the following structure. * On NV40 they are 32 byte long, on NV30 and smaller 16 bytes. @@ -426,89 +652,142 @@ nouveau_object_dma_create(drm_device_t* dev, int channel, int class, entry[5]: set to 0? */ -struct nouveau_object * -nouveau_object_gr_create(drm_device_t* dev, int channel, int class) +int +nouveau_gpuobj_gr_new(drm_device_t *dev, int channel, int class, + nouveau_gpuobj_t **gpuobj) { - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_object *obj; + drm_nouveau_private_t *dev_priv = dev->dev_private; + int ret; - DRM_DEBUG("class=%x\n", class); + DRM_DEBUG("ch%d class=0x%04x\n", channel, class); - obj = nouveau_object_instance_alloc(dev, channel); - if (!obj) { - DRM_ERROR("couldn't allocate context object\n"); - return obj; + ret = nouveau_gpuobj_new(dev, channel, + nouveau_gpuobj_class_instmem_size(dev, class), + 16, + NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, + gpuobj); + if (ret) { + DRM_ERROR("Error creating gpuobj: %d\n", ret); + return ret; } - obj->engine = 1; - obj->class = class; + if (dev_priv->card_type >= NV_50) { + nouveau_gpuobj_del(dev, gpuobj); + DRM_ERROR("stub!\n"); + return DRM_ERR(EINVAL); + } switch (class) { case NV_CLASS_NULL: - INSTANCE_WR(obj->instance, 0, 0x00001030); - INSTANCE_WR(obj->instance, 1, 0xFFFFFFFF); - INSTANCE_WR(obj->instance, 2, 0x00000000); - INSTANCE_WR(obj->instance, 2, 0x00000000); + INSTANCE_WR(*gpuobj, 0, 0x00001030); + INSTANCE_WR(*gpuobj, 1, 0xFFFFFFFF); break; default: if (dev_priv->card_type >= NV_40) { - INSTANCE_WR(obj->instance, 0, obj->class); - INSTANCE_WR(obj->instance, 1, 0x00000000); + INSTANCE_WR(*gpuobj, 0, class); #ifdef __BIG_ENDIAN - INSTANCE_WR(obj->instance, 2, 0x01000000); -#else - INSTANCE_WR(obj->instance, 2, 0x00000000); + INSTANCE_WR(*gpuobj, 2, 0x01000000); #endif - INSTANCE_WR(obj->instance, 3, 0x00000000); - INSTANCE_WR(obj->instance, 4, 0x00000000); - INSTANCE_WR(obj->instance, 5, 0x00000000); - INSTANCE_WR(obj->instance, 6, 0x00000000); - INSTANCE_WR(obj->instance, 7, 0x00000000); } else { #ifdef __BIG_ENDIAN - INSTANCE_WR(obj->instance, 0, obj->class | 0x00080000); + INSTANCE_WR(*gpuobj, 0, class | 0x00080000); #else - INSTANCE_WR(obj->instance, 0, obj->class); + INSTANCE_WR(*gpuobj, 0, class); #endif - INSTANCE_WR(obj->instance, 1, 0x00000000); - INSTANCE_WR(obj->instance, 2, 0x00000000); - INSTANCE_WR(obj->instance, 3, 0x00000000); } } - return obj; + (*gpuobj)->engine = NVOBJ_ENGINE_GR; + (*gpuobj)->class = class; + return 0; } -void -nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj) +static int +nouveau_gpuobj_channel_init_pramin(drm_device_t *dev, int channel) { - nouveau_object_instance_free(dev, obj); - if (obj->handle != ~0) - nouveau_ramht_remove(dev, obj); - drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER); + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + nouveau_gpuobj_t *pramin = NULL; + int size, base, ret; + + DRM_DEBUG("ch%d\n", channel); + + /* Base amount for object storage (4KiB enough?) */ + size = 0x1000; + base = 0; + + /* PGRAPH context */ + + if (dev_priv->card_type == NV_50) { + /* RAMHT, RAMFC, PD, funny header thingo */ + } + + 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->ramin); + if (ret) { + DRM_ERROR("Error allocating channel PRAMIN: %d\n", ret); + return ret; + } + pramin = chan->ramin->gpuobj; + + ret = nouveau_mem_init_heap(&chan->ramin_heap, + pramin->im_pramin->start + base, size); + if (ret) { + DRM_ERROR("Error creating PRAMIN heap: %d\n", ret); + nouveau_gpuobj_ref_del(dev, &chan->ramin); + return ret; + } + + return 0; } int -nouveau_object_init_channel(drm_device_t *dev, int channel, - uint32_t vram_handle, - uint32_t tt_handle) +nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, + uint32_t vram_h, uint32_t tt_h) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_object *gpuobj; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + nouveau_gpuobj_t *vram = NULL, *tt = NULL; int ret; + DRM_DEBUG("ch%d vram=0x%08x tt=0x%08x\n", channel, vram_h, tt_h); + + /* Reserve a block of PRAMIN for the channel + *XXX: maybe on card_type == NV_50) { + ret = nouveau_gpuobj_channel_init_pramin(dev, channel); + if (ret) + return ret; + } + + /* RAMHT */ + if (dev_priv->card_type < NV_50) { + ret = nouveau_gpuobj_ref_add(dev, -1, 0, dev_priv->ramht, + &chan->ramht); + if (ret) + return ret; + } else { + ret = nouveau_gpuobj_new_ref(dev, channel, channel, 0, + 0x8000, 16, + NVOBJ_FLAG_ZERO_ALLOC, + &chan->ramht); + if (ret) + return 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); + if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->fb_available_size, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_VIDMEM, &vram))) { + DRM_ERROR("Error creating VRAM ctxdma: %d\n", ret); + return ret; } - ret = nouveau_ramht_insert(dev, channel, vram_handle, gpuobj); - if (ret) { + if ((ret = nouveau_gpuobj_ref_add(dev, channel, vram_h, vram, NULL))) { DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret); return ret; } @@ -518,17 +797,15 @@ nouveau_object_init_channel(drm_device_t *dev, int channel, 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 ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->agp_available_size, + NV_DMA_ACCESS_RW, NV_DMA_TARGET_AGP, + &tt))) { + DRM_ERROR("Error creating TT ctxdma: %d\n", ret); + return ret; } - ret = nouveau_ramht_insert(dev, channel, tt_handle, gpuobj); - if (ret) { + if ((ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL))) { DRM_ERROR("Error referencing TT ctxdma: %d\n", ret); return ret; } @@ -536,20 +813,34 @@ nouveau_object_init_channel(drm_device_t *dev, int channel, return 0; } -void nouveau_object_cleanup(drm_device_t *dev, int channel) +void +nouveau_gpuobj_channel_takedown(drm_device_t *dev, int channel) { - drm_nouveau_private_t *dev_priv=dev->dev_private; + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + nouveau_gpuobj_ref_t *ref; + + DRM_DEBUG("ch%d\n", channel); - while (dev_priv->fifos[channel].objs) { - nouveau_object_free(dev, dev_priv->fifos[channel].objs); + while ((ref = chan->ramht_refs)) { + chan->ramht_refs = ref->next; + nouveau_gpuobj_ref_del(dev, &ref); } + nouveau_gpuobj_ref_del(dev, &chan->ramht); + + if (chan->ramin_heap) + nouveau_mem_takedown(&chan->ramin_heap); + if (chan->ramin) + nouveau_gpuobj_ref_del(dev, &chan->ramin); + } int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_nouveau_grobj_alloc_t init; - struct nouveau_object *obj; + nouveau_gpuobj_t *gr = NULL; + int ret; DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_grobj_alloc_t __user *) data, sizeof(init)); @@ -561,20 +852,20 @@ int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) } //FIXME: check args, only allow trusted objects to be created + //FIXME: check for pre-existing handle - 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); + if ((ret = nouveau_gpuobj_gr_new(dev, init.channel, init.class, &gr))) { + DRM_ERROR("Error creating gr object: %d (%d/0x%08x)\n", + ret, init.channel, init.handle); + return ret; } - obj = nouveau_object_gr_create(dev, init.channel, init.class); - if (!obj) - return DRM_ERR(ENOMEM); - - if (nouveau_ramht_insert(dev, init.channel, init.handle, obj)) { - nouveau_object_free(dev, obj); - return DRM_ERR(ENOMEM); + if ((ret = nouveau_gpuobj_ref_add(dev, init.channel, 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); + return ret; } return 0; -- cgit v1.2.3 From c806bba4665bb369168ee0b453fa28e2e0bf2a5d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 5 Jul 2007 00:12:33 +1000 Subject: nouveau/nv50: Initial channel/object support Should be OK on G84 for a single channel, multiple channels *almost* work. Untested on G80. --- shared-core/nouveau_object.c | 70 ++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 29 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 79875ca1..a394ae6e 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -76,7 +76,8 @@ nouveau_ramht_hash_handle(drm_device_t *dev, int channel, uint32_t handle) hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1)); handle >>= dev_priv->ramht_bits; } - hash ^= channel << (dev_priv->ramht_bits - 4); + if (dev_priv->card_type < NV_50) + hash ^= channel << (dev_priv->ramht_bits - 4); hash <<= 3; DRM_DEBUG("ch%d handle=0x%08x hash=0x%08x\n", channel, handle, hash); @@ -99,7 +100,7 @@ static int nouveau_ramht_insert(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) { drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[ref->channel]; + struct nouveau_fifo *chan = dev_priv->fifos[ref->channel]; nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; nouveau_gpuobj_t *gpuobj = ref->gpuobj; uint32_t ctx, co, ho; @@ -148,7 +149,7 @@ static void nouveau_ramht_remove(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[ref->channel]; + struct nouveau_fifo *chan = dev_priv->fifos[ref->channel]; nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; uint32_t co, ho; @@ -183,9 +184,11 @@ nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, uint32_t flags, nouveau_gpuobj_t **gpuobj_ret) { drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_engine_func_t *engine = &dev_priv->Engine; struct nouveau_fifo *chan = NULL; nouveau_gpuobj_t *gpuobj; struct mem_block *pramin = NULL; + int ret; DRM_DEBUG("ch%d size=%d align=%d flags=0x%08x\n", channel, size, align, flags); @@ -196,7 +199,7 @@ nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, if (channel >= 0) { if (channel > nouveau_fifo_number(dev)) return DRM_ERR(EINVAL); - chan = &dev_priv->fifos[channel]; + chan = dev_priv->fifos[channel]; } gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER); @@ -230,6 +233,11 @@ nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, return DRM_ERR(EINVAL); } + if (!chan && (ret = engine->instmem.populate(dev, gpuobj, &size))) { + nouveau_gpuobj_del(dev, &gpuobj); + return ret; + } + /* Allocate a chunk of the PRAMIN aperture */ gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size, drm_order(align), @@ -240,14 +248,9 @@ nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, } gpuobj->im_pramin->flags = NOUVEAU_MEM_INSTANCE; - /* On NV50 the PRAMIN aperture is paged. When allocating from the - * global instmem heap, alloc and bind VRAM pages into the PRAMIN - * aperture. - */ - if (!chan && dev_priv->card_type >= NV_50) { - DRM_ERROR("back aperture with vram pages\n"); + if (!chan && (ret = engine->instmem.bind(dev, gpuobj))) { nouveau_gpuobj_del(dev, &gpuobj); - return DRM_ERR(EINVAL); + return ret; } if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { @@ -285,6 +288,7 @@ void nouveau_gpuobj_takedown(drm_device_t *dev) int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj) { drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_engine_func_t *engine = &dev_priv->Engine; nouveau_gpuobj_t *gpuobj; DRM_DEBUG("gpuobj %p\n", pgpuobj ? *pgpuobj : NULL); @@ -298,6 +302,8 @@ int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj) return DRM_ERR(EINVAL); } + engine->instmem.clear(dev, gpuobj); + if (gpuobj->im_pramin) { if (gpuobj->flags & NVOBJ_FLAG_FAKE) drm_free(gpuobj->im_pramin, sizeof(*gpuobj->im_pramin), @@ -306,9 +312,6 @@ int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj) nouveau_mem_free_block(gpuobj->im_pramin); } - if (gpuobj->im_backing) - nouveau_mem_free(dev, gpuobj->im_backing); - if (gpuobj->next) gpuobj->next->prev = gpuobj->prev; if (gpuobj->prev) @@ -342,7 +345,7 @@ nouveau_gpuobj_instance_get(drm_device_t *dev, int channel, /* NV50 channel-local instance */ if (channel > 0) { - cpramin = dev_priv->fifos[channel].ramin->gpuobj; + cpramin = dev_priv->fifos[channel]->ramin->gpuobj; *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start; return 0; } @@ -358,7 +361,7 @@ nouveau_gpuobj_instance_get(drm_device_t *dev, int channel, return 0; } else { /* ...from local heap */ - cpramin = dev_priv->fifos[gpuobj->im_channel].ramin->gpuobj; + cpramin = dev_priv->fifos[gpuobj->im_channel]->ramin->gpuobj; *inst = (cpramin->im_backing->start - dev_priv->fb_phys) + (gpuobj->im_pramin->start - cpramin->im_pramin->start); return 0; @@ -385,7 +388,7 @@ nouveau_gpuobj_ref_add(drm_device_t *dev, int channel, uint32_t handle, if (channel >= 0) { if (channel > nouveau_fifo_number(dev)) return DRM_ERR(EINVAL); - chan = &dev_priv->fifos[channel]; + chan = dev_priv->fifos[channel]; } else if (!ref_ret) return DRM_ERR(EINVAL); @@ -591,9 +594,10 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, INSTANCE_WR(*gpuobj, 2, frame | pte_flags); INSTANCE_WR(*gpuobj, 3, frame | pte_flags); } else { - nouveau_gpuobj_del(dev, gpuobj); - DRM_ERROR("stub\n"); - return DRM_ERR(EINVAL); + INSTANCE_WR(*gpuobj, 0, 0x00190000 | class); + INSTANCE_WR(*gpuobj, 1, offset + size - 1); + INSTANCE_WR(*gpuobj, 2, offset); + INSTANCE_WR(*gpuobj, 5, 0x00010000); } (*gpuobj)->engine = NVOBJ_ENGINE_SW; @@ -672,11 +676,9 @@ nouveau_gpuobj_gr_new(drm_device_t *dev, int channel, int class, } if (dev_priv->card_type >= NV_50) { - nouveau_gpuobj_del(dev, gpuobj); - DRM_ERROR("stub!\n"); - return DRM_ERR(EINVAL); - } - + INSTANCE_WR(*gpuobj, 0, class); + INSTANCE_WR(*gpuobj, 5, 0x00010000); + } else { switch (class) { case NV_CLASS_NULL: INSTANCE_WR(*gpuobj, 0, 0x00001030); @@ -696,6 +698,7 @@ nouveau_gpuobj_gr_new(drm_device_t *dev, int channel, int class, #endif } } + } (*gpuobj)->engine = NVOBJ_ENGINE_GR; (*gpuobj)->class = class; @@ -706,7 +709,7 @@ static int nouveau_gpuobj_channel_init_pramin(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; nouveau_gpuobj_t *pramin = NULL; int size, base, ret; @@ -719,7 +722,16 @@ nouveau_gpuobj_channel_init_pramin(drm_device_t *dev, int channel) /* PGRAPH context */ if (dev_priv->card_type == NV_50) { - /* RAMHT, RAMFC, PD, funny header thingo */ + /* Various fixed table thingos */ + size += 0x1400; /* mostly unknown stuff */ + size += 0x4000; /* vm pd */ + base = 0x6000; + /* RAMHT, not sure about setting size yet, 32KiB to be safe */ + size += 0x8000; + /* RAMFC */ + size += 0x1000; + /* PGRAPH context */ + size += 0x60000; } DRM_DEBUG("ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n", @@ -748,7 +760,7 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, uint32_t vram_h, uint32_t tt_h) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; nouveau_gpuobj_t *vram = NULL, *tt = NULL; int ret; @@ -817,7 +829,7 @@ void nouveau_gpuobj_channel_takedown(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; nouveau_gpuobj_ref_t *ref; DRM_DEBUG("ch%d\n", channel); -- cgit v1.2.3 From 31e33813e8c1b085683e68524e680882368e59a9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 9 Jul 2007 20:02:14 +1000 Subject: nouveau: Don't be so strict on dev_private; nouveau_gpuobj_t *cpramin; - if ((channel > 0) && gpuobj->im_channel != channel) { - DRM_ERROR("Channel mismatch: obj %d, ref %d\n", - gpuobj->im_channel, channel); - return DRM_ERR(EINVAL); - } - /* card_type < NV_50) { *inst = gpuobj->im_pramin->start; return 0; } + if ((channel > 0) && gpuobj->im_channel != channel) { + DRM_ERROR("Channel mismatch: obj %d, ref %d\n", + gpuobj->im_channel, channel); + return DRM_ERR(EINVAL); + } + /* NV50 channel-local instance */ if (channel > 0) { cpramin = dev_priv->fifos[channel]->ramin->gpuobj; -- cgit v1.2.3 From 694e1c5c3f768436651ddf95e11ab5a89ccc8ffa Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Wed, 11 Jul 2007 02:35:10 +0200 Subject: Added support for PCIGART for PCI(E) cards. Bumped DRM interface patchlevel. --- shared-core/nouveau_object.c | 161 ++++++++++++++++++++++++++++++------------- 1 file changed, 112 insertions(+), 49 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index bf811b4b..dcb29b40 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -515,6 +515,20 @@ nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size, return 0; } + +static int +nouveau_gpuobj_class_instmem_size(drm_device_t *dev, int class) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + /*XXX: dodgy hack for now */ + if (dev_priv->card_type >= NV_50) + return 24; + if (dev_priv->card_type >= NV_40) + return 32; + return 16; +} + /* DMA objects are used to reference a piece of memory in the framebuffer, PCI or AGP address space. Each object is 16 bytes big @@ -528,31 +542,20 @@ nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size, 17:16 target: 0 NV memory, 1 NV memory tiled, 2 PCI, 3 AGP 31:20 dma adjust (bits 0-11 of the address) entry[1] - dma limit - entry[2] + dma limit (size of transfer) + entry[X] 1 0 readonly, 1 readwrite - 31:12 dma frame address (bits 12-31 of the address) + 31:12 dma frame address of the page (bits 12-31 of the address) + entry[N] + page table terminator, same value as the first pte, as does nvidia + rivatv uses 0xffffffff - Non linear page tables seem to need a list of frame addresses afterwards, - the rivatv project has some info on this. + Non linear page tables need a list of frame addresses afterwards, + the rivatv project has some info on this. The method below creates a DMA object in instance RAM and returns a handle to it that can be used to set up context objects. */ - -static int -nouveau_gpuobj_class_instmem_size(drm_device_t *dev, int class) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - - /*XXX: dodgy hack for now */ - if (dev_priv->card_type >= NV_50) - return 24; - if (dev_priv->card_type >= NV_40) - return 32; - return 16; -} - int nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, uint64_t offset, uint64_t size, int access, int target, @@ -560,13 +563,28 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, { drm_nouveau_private_t *dev_priv = dev->dev_private; int ret; - + uint32_t is_scatter_gather = 0; + DRM_DEBUG("ch%d class=0x%04x offset=0x%llx size=0x%llx\n", channel, class, offset, size); DRM_DEBUG("access=%d target=%d\n", access, target); + switch (target) { + case NV_DMA_TARGET_AGP: + offset += dev_priv->agp_phys; + break; + case NV_DMA_TARGET_PCI_NONLINEAR: + /*assume the "offset" is a virtual memory address*/ + is_scatter_gather = 1; + /*put back the right value*/ + target = NV_DMA_TARGET_PCI; + break; + default: + break; + } + ret = nouveau_gpuobj_new(dev, channel, - nouveau_gpuobj_class_instmem_size(dev, class), + is_scatter_gather ? ((((size + PAGE_SIZE - 1) / PAGE_SIZE) << 2) + 12) : nouveau_gpuobj_class_instmem_size(dev, class), 16, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, gpuobj); @@ -577,22 +595,53 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, if (dev_priv->card_type < NV_50) { uint32_t frame, adjust, pte_flags = 0; - - if (target == NV_DMA_TARGET_AGP) - offset += dev_priv->agp_phys; - if (access != NV_DMA_ACCESS_RO) - pte_flags |= (1<<1); - frame = offset & ~0x00000fff; adjust = offset & 0x00000fff; - - INSTANCE_WR(*gpuobj, 0, ((1<<12) | (1<<13) | - (adjust << 20) | + if (access != NV_DMA_ACCESS_RO) + pte_flags |= (1<<1); + + if ( ! is_scatter_gather ) + { + frame = offset & ~0x00000fff; + + INSTANCE_WR(*gpuobj, 0, ((1<<12) | (1<<13) | + (adjust << 20) | (access << 14) | (target << 16) | class)); - INSTANCE_WR(*gpuobj, 1, size - 1); - INSTANCE_WR(*gpuobj, 2, frame | pte_flags); - INSTANCE_WR(*gpuobj, 3, frame | pte_flags); + INSTANCE_WR(*gpuobj, 1, size - 1); + INSTANCE_WR(*gpuobj, 2, frame | pte_flags); + INSTANCE_WR(*gpuobj, 3, frame | pte_flags); + } + else + { + uint32_t instance_offset; + uint32_t bus_addr; + size = (uint32_t) size; + + DRM_DEBUG("Creating PCI DMA object using virtual zone starting at 0x%08x, size %d\n", (uint32_t) offset, (uint32_t)size); + INSTANCE_WR(*gpuobj, 0, ((1<<12) | (0<<13) | + (adjust << 20) | + (access << 14) | + (target << 16) | + class)); + INSTANCE_WR(*gpuobj, 1, size-1); + + /*write starting at the third dword*/ + instance_offset = 2; + + /*for each PAGE, get its bus address, fill in the page table entry, and advance*/ + while ( size > 0 ) { + bus_addr = (uint32_t) page_address(vmalloc_to_page((void *) (uint32_t) offset)); + bus_addr |= (offset & ~PAGE_MASK); + bus_addr = virt_to_bus((void *)bus_addr); + frame = bus_addr & ~0x00000FFF; + INSTANCE_WR(*gpuobj, instance_offset, frame | pte_flags); + offset += PAGE_SIZE; + instance_offset ++; + size -= PAGE_SIZE; + } + + } } else { INSTANCE_WR(*gpuobj, 0, 0x00190000 | class); INSTANCE_WR(*gpuobj, 1, offset + size - 1); @@ -804,24 +853,38 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, return ret; } - /* non-AGP unimplemented */ - if (dev_priv->agp_heap == NULL) - return 0; - - /* GART ctxdma */ - if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, - 0, dev_priv->agp_available_size, - NV_DMA_ACCESS_RW, NV_DMA_TARGET_AGP, - &tt))) { - DRM_ERROR("Error creating TT ctxdma: %d\n", ret); - return ret; + if (dev_priv->agp_heap) { + /* AGPGART ctxdma */ + if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->agp_available_size, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_AGP, &tt))) { + DRM_ERROR("Error creating AGP TT ctxdma: %d\n", DRM_ERR(ENOMEM)); + return DRM_ERR(ENOMEM); + } + + ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL); + if (ret) { + DRM_ERROR("Error referencing AGP TT ctxdma: %d\n", ret); + return ret; + } } - - if ((ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL))) { - DRM_ERROR("Error referencing TT ctxdma: %d\n", ret); - return ret; + else { + /*PCI*/ + if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + (unsigned int) dev->sg->virtual, dev->sg->pages * PAGE_SIZE, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_PCI_NONLINEAR, &tt))) { + DRM_ERROR("Error creating PCI TT ctxdma: %d\n", DRM_ERR(ENOMEM)); + return DRM_ERR(ENOMEM); + } + + ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL); + if (ret) { + DRM_ERROR("Error referencing PCI TT ctxdma: %d\n", ret); + return ret; + } } - return 0; } -- cgit v1.2.3 From 13e1377044d581d692af77656e3bc32c9eb183f7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 11 Jul 2007 12:38:48 +1000 Subject: nouveau: Some checks on userspace object handles. --- shared-core/nouveau_object.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index dcb29b40..82944c2b 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -470,6 +470,26 @@ nouveau_gpuobj_new_ref(drm_device_t *dev, int oc, int rc, uint32_t handle, return 0; } +static int +nouveau_gpuobj_ref_find(drm_device_t *dev, int channel, uint32_t handle, + nouveau_gpuobj_ref_t **ref_ret) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + nouveau_gpuobj_ref_t *ref = chan->ramht_refs; + + while (ref) { + if (ref->handle == handle) { + if (ref_ret) + *ref_ret = ref; + return 0; + } + ref = ref->next; + } + + return DRM_ERR(EINVAL); +} + int nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size, uint32_t flags, nouveau_gpuobj_t **pgpuobj, @@ -927,7 +947,11 @@ int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) } //FIXME: check args, only allow trusted objects to be created - //FIXME: check for pre-existing handle + + if (init.handle == ~0) + return DRM_ERR(EINVAL); + if (nouveau_gpuobj_ref_find(dev, init.channel, init.handle, NULL) == 0) + return DRM_ERR(EEXIST); if ((ret = nouveau_gpuobj_gr_new(dev, init.channel, init.class, &gr))) { DRM_ERROR("Error creating gr object: %d (%d/0x%08x)\n", -- cgit v1.2.3 From b301a9051b3fd9ad3dce6bcf32b06da7953a8b91 Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Wed, 11 Jul 2007 15:01:37 +0200 Subject: NV50 will not attempt to use PCIGART now --- shared-core/nouveau_object.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 82944c2b..0fe32fda 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -890,6 +890,8 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, } } else { + if ( dev_priv -> card_type >= NV_50 ) return 0; /*no PCIGART for NV50*/ + /*PCI*/ if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, (unsigned int) dev->sg->virtual, dev->sg->pages * PAGE_SIZE, -- cgit v1.2.3 From 5fbdf9da8bda996c0a474d13fe69d260f12ffce7 Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Thu, 12 Jul 2007 02:35:39 +0200 Subject: fixed object creation code to not Oops on 64bits, worked around memalloc not working on 64bit for PCIGART --- shared-core/nouveau_object.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 0fe32fda..4f7ad111 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -635,10 +635,10 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, else { uint32_t instance_offset; - uint32_t bus_addr; + uint64_t bus_addr; size = (uint32_t) size; - DRM_DEBUG("Creating PCI DMA object using virtual zone starting at 0x%08x, size %d\n", (uint32_t) offset, (uint32_t)size); + DRM_DEBUG("Creating PCI DMA object using virtual zone starting at %#llx, size %d\n", offset, (uint32_t)size); INSTANCE_WR(*gpuobj, 0, ((1<<12) | (0<<13) | (adjust << 20) | (access << 14) | @@ -651,10 +651,37 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, /*for each PAGE, get its bus address, fill in the page table entry, and advance*/ while ( size > 0 ) { - bus_addr = (uint32_t) page_address(vmalloc_to_page((void *) (uint32_t) offset)); + bus_addr = vmalloc_to_page(offset); + if ( ! bus_addr ) + { + DRM_ERROR("Couldn't map virtual address %#llx to a page number\n", offset); + nouveau_gpuobj_del(dev, gpuobj); + return DRM_ERR(ENOMEM); + } + bus_addr = (uint64_t) page_address(bus_addr); + if ( ! bus_addr ) + { + DRM_ERROR("Couldn't find page address for address %#llx\n", offset); + nouveau_gpuobj_del(dev, gpuobj); + return DRM_ERR(ENOMEM); + } bus_addr |= (offset & ~PAGE_MASK); bus_addr = virt_to_bus((void *)bus_addr); - frame = bus_addr & ~0x00000FFF; + if ( ! bus_addr ) + { + DRM_ERROR("Couldn't get bus address for %#llx\n", offset); + nouveau_gpuobj_del(dev, gpuobj); + return DRM_ERR(ENOMEM); + } + + /*if ( bus_addr >= 1 << 32 ) + { + DRM_ERROR("Bus address %#llx is over 32 bits, Nvidia cards cannot address it !\n", bus_addr); + nouveau_gpuobj_del(dev, gpuobj); + return DRM_ERR(EINVAL); + }*/ + + frame = (uint32_t) bus_addr & ~0x00000FFF; INSTANCE_WR(*gpuobj, instance_offset, frame | pte_flags); offset += PAGE_SIZE; instance_offset ++; @@ -894,11 +921,11 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, /*PCI*/ if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, - (unsigned int) dev->sg->virtual, dev->sg->pages * PAGE_SIZE, + dev->sg->virtual, dev->sg->pages * PAGE_SIZE, NV_DMA_ACCESS_RW, NV_DMA_TARGET_PCI_NONLINEAR, &tt))) { DRM_ERROR("Error creating PCI TT ctxdma: %d\n", DRM_ERR(ENOMEM)); - return DRM_ERR(ENOMEM); + return 0; //this is noncritical } ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL); -- cgit v1.2.3 From 750371cb6ea9a64c9d4d4d3b9716c3c68d810d48 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 12 Jul 2007 10:15:16 +1000 Subject: nouveau: separate region_offset into map_handle and offset. --- shared-core/nouveau_object.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 4f7ad111..e8ed708f 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -357,12 +357,12 @@ nouveau_gpuobj_instance_get(drm_device_t *dev, int channel, DRM_ERROR("AII, no VRAM backing gpuobj\n"); return DRM_ERR(EINVAL); } - *inst = gpuobj->im_backing->start - dev_priv->fb_phys; + *inst = gpuobj->im_backing->start; return 0; } else { /* ...from local heap */ cpramin = dev_priv->fifos[gpuobj->im_channel]->ramin->gpuobj; - *inst = (cpramin->im_backing->start - dev_priv->fb_phys) + + *inst = cpramin->im_backing->start + (gpuobj->im_pramin->start - cpramin->im_pramin->start); return 0; } @@ -917,7 +917,7 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, } } else { - if ( dev_priv -> card_type >= NV_50 ) return 0; /*no PCIGART for NV50*/ + if (dev_priv -> card_type >= NV_50 ) return 0; /*no PCIGART for NV50*/ /*PCI*/ if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, -- cgit v1.2.3 From af317f1cc7136dbf03b39ced64c42202703c5066 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 12 Jul 2007 11:55:47 +1000 Subject: nouveau: mem_alloc() returns offsets, not absolute addresses now. --- shared-core/nouveau_object.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index e8ed708f..16b38e95 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -646,6 +646,8 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, class)); INSTANCE_WR(*gpuobj, 1, size-1); + offset += dev->sg->virtual; + /*write starting at the third dword*/ instance_offset = 2; @@ -921,7 +923,7 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, /*PCI*/ if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, - dev->sg->virtual, dev->sg->pages * PAGE_SIZE, + 0, dev->sg->pages * PAGE_SIZE, NV_DMA_ACCESS_RW, NV_DMA_TARGET_PCI_NONLINEAR, &tt))) { DRM_ERROR("Error creating PCI TT ctxdma: %d\n", DRM_ERR(ENOMEM)); -- cgit v1.2.3 From 0029713451af6f5f216079775ff77cae9b423c0e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 13 Jul 2007 15:09:31 +1000 Subject: nouveau: nuke internal typedefs, and drm_device_t use. --- shared-core/nouveau_object.c | 133 ++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 66 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 16b38e95..c5697d8e 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -66,9 +66,9 @@ is given as: */ static uint32_t -nouveau_ramht_hash_handle(drm_device_t *dev, int channel, uint32_t handle) +nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle) { - drm_nouveau_private_t *dev_priv=dev->dev_private; + struct drm_nouveau_private *dev_priv=dev->dev_private; uint32_t hash = 0; int i; @@ -85,10 +85,10 @@ nouveau_ramht_hash_handle(drm_device_t *dev, int channel, uint32_t handle) } static int -nouveau_ramht_entry_valid(drm_device_t *dev, nouveau_gpuobj_t *ramht, +nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht, uint32_t offset) { - drm_nouveau_private_t *dev_priv=dev->dev_private; + struct drm_nouveau_private *dev_priv=dev->dev_private; uint32_t ctx = INSTANCE_RD(ramht, (offset + 4)/4); if (dev_priv->card_type < NV_40) @@ -97,12 +97,12 @@ nouveau_ramht_entry_valid(drm_device_t *dev, nouveau_gpuobj_t *ramht, } static int -nouveau_ramht_insert(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) +nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) { - drm_nouveau_private_t *dev_priv=dev->dev_private; + struct drm_nouveau_private *dev_priv=dev->dev_private; struct nouveau_fifo *chan = dev_priv->fifos[ref->channel]; - nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; - nouveau_gpuobj_t *gpuobj = ref->gpuobj; + struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; + struct nouveau_gpuobj *gpuobj = ref->gpuobj; uint32_t ctx, co, ho; if (!ramht) { @@ -146,11 +146,11 @@ nouveau_ramht_insert(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) } static void -nouveau_ramht_remove(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) +nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) { - drm_nouveau_private_t *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo *chan = dev_priv->fifos[ref->channel]; - nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; + struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; uint32_t co, ho; if (!ramht) { @@ -180,13 +180,13 @@ nouveau_ramht_remove(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) } int -nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, - uint32_t flags, nouveau_gpuobj_t **gpuobj_ret) +nouveau_gpuobj_new(struct drm_device *dev, int channel, int size, int align, + uint32_t flags, struct nouveau_gpuobj **gpuobj_ret) { - drm_nouveau_private_t *dev_priv = dev->dev_private; - nouveau_engine_func_t *engine = &dev_priv->Engine; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine_func *engine = &dev_priv->Engine; struct nouveau_fifo *chan = NULL; - nouveau_gpuobj_t *gpuobj; + struct nouveau_gpuobj *gpuobj; struct mem_block *pramin = NULL; int ret; @@ -270,10 +270,10 @@ nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, return 0; } -void nouveau_gpuobj_takedown(drm_device_t *dev) +void nouveau_gpuobj_takedown(struct drm_device *dev) { - drm_nouveau_private_t *dev_priv = dev->dev_private; - nouveau_gpuobj_t *gpuobj = NULL; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *gpuobj = NULL; DRM_DEBUG("\n"); @@ -285,11 +285,11 @@ void nouveau_gpuobj_takedown(drm_device_t *dev) } } -int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj) +int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) { - drm_nouveau_private_t *dev_priv = dev->dev_private; - nouveau_engine_func_t *engine = &dev_priv->Engine; - nouveau_gpuobj_t *gpuobj; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine_func *engine = &dev_priv->Engine; + struct nouveau_gpuobj *gpuobj; DRM_DEBUG("gpuobj %p\n", pgpuobj ? *pgpuobj : NULL); @@ -325,11 +325,11 @@ int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj) } static int -nouveau_gpuobj_instance_get(drm_device_t *dev, int channel, - nouveau_gpuobj_t *gpuobj, uint32_t *inst) +nouveau_gpuobj_instance_get(struct drm_device *dev, int channel, + struct nouveau_gpuobj *gpuobj, uint32_t *inst) { - drm_nouveau_private_t *dev_priv = dev->dev_private; - nouveau_gpuobj_t *cpramin; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *cpramin; /* card_type < NV_50) { @@ -371,12 +371,12 @@ nouveau_gpuobj_instance_get(drm_device_t *dev, int channel, } int -nouveau_gpuobj_ref_add(drm_device_t *dev, int channel, uint32_t handle, - nouveau_gpuobj_t *gpuobj, nouveau_gpuobj_ref_t **ref_ret) +nouveau_gpuobj_ref_add(struct drm_device *dev, int channel, uint32_t handle, + struct nouveau_gpuobj *gpuobj, struct nouveau_gpuobj_ref **ref_ret) { - drm_nouveau_private_t *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo *chan = NULL; - nouveau_gpuobj_ref_t *ref; + struct nouveau_gpuobj_ref *ref; uint32_t instance; int ret; @@ -424,9 +424,9 @@ nouveau_gpuobj_ref_add(drm_device_t *dev, int channel, uint32_t handle, return 0; } -int nouveau_gpuobj_ref_del(drm_device_t *dev, nouveau_gpuobj_ref_t **pref) +int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **pref) { - nouveau_gpuobj_ref_t *ref; + struct nouveau_gpuobj_ref *ref; DRM_DEBUG("ref %p\n", pref ? *pref : NULL); @@ -452,11 +452,11 @@ int nouveau_gpuobj_ref_del(drm_device_t *dev, nouveau_gpuobj_ref_t **pref) } int -nouveau_gpuobj_new_ref(drm_device_t *dev, int oc, int rc, uint32_t handle, +nouveau_gpuobj_new_ref(struct drm_device *dev, int oc, int rc, uint32_t handle, int size, int align, uint32_t flags, - nouveau_gpuobj_ref_t **ref) + struct nouveau_gpuobj_ref **ref) { - nouveau_gpuobj_t *gpuobj = NULL; + struct nouveau_gpuobj *gpuobj = NULL; int ret; if ((ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj))) @@ -471,12 +471,12 @@ nouveau_gpuobj_new_ref(drm_device_t *dev, int oc, int rc, uint32_t handle, } static int -nouveau_gpuobj_ref_find(drm_device_t *dev, int channel, uint32_t handle, - nouveau_gpuobj_ref_t **ref_ret) +nouveau_gpuobj_ref_find(struct drm_device *dev, int channel, uint32_t handle, + struct nouveau_gpuobj_ref **ref_ret) { - drm_nouveau_private_t *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo *chan = dev_priv->fifos[channel]; - nouveau_gpuobj_ref_t *ref = chan->ramht_refs; + struct nouveau_gpuobj_ref *ref = chan->ramht_refs; while (ref) { if (ref->handle == handle) { @@ -491,12 +491,12 @@ nouveau_gpuobj_ref_find(drm_device_t *dev, int channel, uint32_t handle, } int -nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size, - uint32_t flags, nouveau_gpuobj_t **pgpuobj, - nouveau_gpuobj_ref_t **pref) +nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size, + uint32_t flags, struct nouveau_gpuobj **pgpuobj, + struct nouveau_gpuobj_ref **pref) { - drm_nouveau_private_t *dev_priv = dev->dev_private; - nouveau_gpuobj_t *gpuobj = NULL; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *gpuobj = NULL; int i; DRM_DEBUG("offset=0x%08x size=0x%08x flags=0x%08x\n", @@ -537,9 +537,9 @@ nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size, static int -nouveau_gpuobj_class_instmem_size(drm_device_t *dev, int class) +nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class) { - drm_nouveau_private_t *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; /*XXX: dodgy hack for now */ if (dev_priv->card_type >= NV_50) @@ -577,11 +577,11 @@ nouveau_gpuobj_class_instmem_size(drm_device_t *dev, int class) to it that can be used to set up context objects. */ int -nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, +nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, uint64_t offset, uint64_t size, int access, int target, - nouveau_gpuobj_t **gpuobj) + struct nouveau_gpuobj **gpuobj) { - drm_nouveau_private_t *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; int ret; uint32_t is_scatter_gather = 0; @@ -755,10 +755,10 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, set to 0? */ int -nouveau_gpuobj_gr_new(drm_device_t *dev, int channel, int class, - nouveau_gpuobj_t **gpuobj) +nouveau_gpuobj_gr_new(struct drm_device *dev, int channel, int class, + struct nouveau_gpuobj **gpuobj) { - drm_nouveau_private_t *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; int ret; DRM_DEBUG("ch%d class=0x%04x\n", channel, class); @@ -804,11 +804,11 @@ nouveau_gpuobj_gr_new(drm_device_t *dev, int channel, int class, } static int -nouveau_gpuobj_channel_init_pramin(drm_device_t *dev, int channel) +nouveau_gpuobj_channel_init_pramin(struct drm_device *dev, int channel) { - drm_nouveau_private_t *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo *chan = dev_priv->fifos[channel]; - nouveau_gpuobj_t *pramin = NULL; + struct nouveau_gpuobj *pramin = NULL; int size, base, ret; DRM_DEBUG("ch%d\n", channel); @@ -854,12 +854,12 @@ nouveau_gpuobj_channel_init_pramin(drm_device_t *dev, int channel) } int -nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, +nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, uint32_t vram_h, uint32_t tt_h) { - drm_nouveau_private_t *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo *chan = dev_priv->fifos[channel]; - nouveau_gpuobj_t *vram = NULL, *tt = NULL; + struct nouveau_gpuobj *vram = NULL, *tt = NULL; int ret; DRM_DEBUG("ch%d vram=0x%08x tt=0x%08x\n", channel, vram_h, tt_h); @@ -940,11 +940,11 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, } void -nouveau_gpuobj_channel_takedown(drm_device_t *dev, int channel) +nouveau_gpuobj_channel_takedown(struct drm_device *dev, int channel) { - drm_nouveau_private_t *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo *chan = dev_priv->fifos[channel]; - nouveau_gpuobj_ref_t *ref; + struct nouveau_gpuobj_ref *ref; DRM_DEBUG("ch%d\n", channel); @@ -964,12 +964,13 @@ nouveau_gpuobj_channel_takedown(drm_device_t *dev, int channel) int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) { DRM_DEVICE; - drm_nouveau_grobj_alloc_t init; - nouveau_gpuobj_t *gr = NULL; + struct drm_nouveau_grobj_alloc init; + struct nouveau_gpuobj *gr = NULL; int ret; - DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_grobj_alloc_t __user *) - data, sizeof(init)); + DRM_COPY_FROM_USER_IOCTL(init, + (struct drm_nouveau_grobj_alloc_t __user*)data, + sizeof(init)); if (!nouveau_fifo_owner(dev, filp, init.channel)) { DRM_ERROR("pid %d doesn't own channel %d\n", -- cgit v1.2.3 From 5ae3ad4f015aa072180a0c55255832be4e7557cf Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Fri, 13 Jul 2007 15:57:17 +0200 Subject: now attempting to create PCI object only when there is a pci_heap --- shared-core/nouveau_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index c5697d8e..aab2e3ac 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -918,7 +918,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, return ret; } } - else { + else if ( dev_priv->pci_heap) { if (dev_priv -> card_type >= NV_50 ) return 0; /*no PCIGART for NV50*/ /*PCI*/ -- cgit v1.2.3 From aa6d9199fa7b0cbe04a936312db7be75bb53bdc8 Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Fri, 13 Jul 2007 20:51:52 +0200 Subject: applied patch from Ian Romanick fixing PCI DMA object creation code --- shared-core/nouveau_object.c | 77 +++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 40 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index aab2e3ac..146c4f1c 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -585,6 +585,11 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, int ret; uint32_t is_scatter_gather = 0; + /* Total number of pages covered by the request. + */ + const unsigned int page_count = (size + PAGE_SIZE - 1) / PAGE_SIZE; + + DRM_DEBUG("ch%d class=0x%04x offset=0x%llx size=0x%llx\n", channel, class, offset, size); DRM_DEBUG("access=%d target=%d\n", access, target); @@ -604,7 +609,7 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, } ret = nouveau_gpuobj_new(dev, channel, - is_scatter_gather ? ((((size + PAGE_SIZE - 1) / PAGE_SIZE) << 2) + 12) : nouveau_gpuobj_class_instmem_size(dev, class), + is_scatter_gather ? ((page_count << 2) + 12) : nouveau_gpuobj_class_instmem_size(dev, class), 16, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, gpuobj); @@ -634,9 +639,19 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, } else { + /* Intial page entry in the scatter-gather area that + * corresponds to the base offset + */ + unsigned int idx = offset / PAGE_SIZE; + uint32_t instance_offset; - uint64_t bus_addr; - size = (uint32_t) size; + unsigned int i; + + if ((idx + page_count) > dev->sg->pages) { + DRM_ERROR("Requested page range exceedes " + "allocated scatter-gather range!"); + return DRM_ERR(E2BIG); + } DRM_DEBUG("Creating PCI DMA object using virtual zone starting at %#llx, size %d\n", offset, (uint32_t)size); INSTANCE_WR(*gpuobj, 0, ((1<<12) | (0<<13) | @@ -644,52 +659,34 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, (access << 14) | (target << 16) | class)); - INSTANCE_WR(*gpuobj, 1, size-1); + INSTANCE_WR(*gpuobj, 1, (uint32_t) size-1); - offset += dev->sg->virtual; /*write starting at the third dword*/ instance_offset = 2; /*for each PAGE, get its bus address, fill in the page table entry, and advance*/ - while ( size > 0 ) { - bus_addr = vmalloc_to_page(offset); - if ( ! bus_addr ) - { - DRM_ERROR("Couldn't map virtual address %#llx to a page number\n", offset); - nouveau_gpuobj_del(dev, gpuobj); - return DRM_ERR(ENOMEM); + for (i = 0; i < page_count; i++) { + if (dev->sg->busaddr[idx] == 0) { + dev->sg->busaddr[idx] = + pci_map_page(dev->pdev, + dev->sg->pagelist[idx], + 0, + DMA_31BIT_MASK, + DMA_BIDIRECTIONAL); + + if (dev->sg->busaddr[idx] == 0) { + return DRM_ERR(ENOMEM); } - bus_addr = (uint64_t) page_address(bus_addr); - if ( ! bus_addr ) - { - DRM_ERROR("Couldn't find page address for address %#llx\n", offset); - nouveau_gpuobj_del(dev, gpuobj); - return DRM_ERR(ENOMEM); - } - bus_addr |= (offset & ~PAGE_MASK); - bus_addr = virt_to_bus((void *)bus_addr); - if ( ! bus_addr ) - { - DRM_ERROR("Couldn't get bus address for %#llx\n", offset); - nouveau_gpuobj_del(dev, gpuobj); - return DRM_ERR(ENOMEM); - } - - /*if ( bus_addr >= 1 << 32 ) - { - DRM_ERROR("Bus address %#llx is over 32 bits, Nvidia cards cannot address it !\n", bus_addr); - nouveau_gpuobj_del(dev, gpuobj); - return DRM_ERR(EINVAL); - }*/ - - frame = (uint32_t) bus_addr & ~0x00000FFF; - INSTANCE_WR(*gpuobj, instance_offset, frame | pte_flags); - offset += PAGE_SIZE; - instance_offset ++; - size -= PAGE_SIZE; } + frame = (uint32_t) dev->sg->busaddr[idx]; + INSTANCE_WR(*gpuobj, instance_offset, + frame | pte_flags); + + idx++; + instance_offset ++; + } } } else { INSTANCE_WR(*gpuobj, 0, 0x00190000 | class); -- cgit v1.2.3 From 70a8a60a3e81c18f9c6485102cb226c340c3cd73 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 16 Jul 2007 10:56:43 -0700 Subject: Correct errors in the usage of pci_map_page. With these changes the driver no longer instantly hard-locks a 6600LE on a PowerPC G5. I haven't tested any 3D apps yet. --- shared-core/nouveau_object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 146c4f1c..ea0edb08 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -672,10 +672,10 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, pci_map_page(dev->pdev, dev->sg->pagelist[idx], 0, - DMA_31BIT_MASK, + PAGE_SIZE, DMA_BIDIRECTIONAL); - if (dev->sg->busaddr[idx] == 0) { + if (dma_mapping_error(dev->sg->busaddr[idx])) { return DRM_ERR(ENOMEM); } } -- cgit v1.2.3 From ec67c2def9af16bf9252d6742aec815b817f135a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 15 Jul 2007 17:18:15 +1000 Subject: nouveau: G8x PCIEGART Actually a NV04-NV50 ttm backend for both PCI and PCIEGART, but PCIGART support for G8X using the current mm has been hacked on top of it. --- shared-core/nouveau_object.c | 136 ++++++++++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 35 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index ea0edb08..f0025d7a 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -596,7 +596,7 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, switch (target) { case NV_DMA_TARGET_AGP: - offset += dev_priv->agp_phys; + offset += dev_priv->gart_info.aper_base; break; case NV_DMA_TARGET_PCI_NONLINEAR: /*assume the "offset" is a virtual memory address*/ @@ -689,10 +689,20 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, } } } else { - INSTANCE_WR(*gpuobj, 0, 0x00190000 | class); + uint32_t flags0, flags5; + + if (target == NV_DMA_TARGET_VIDMEM) { + flags0 = 0x00190000; + flags5 = 0x00010000; + } else { + flags0 = 0x7fc00000; + flags5 = 0x00080000; + } + + INSTANCE_WR(*gpuobj, 0, flags0 | class); INSTANCE_WR(*gpuobj, 1, offset + size - 1); INSTANCE_WR(*gpuobj, 2, offset); - INSTANCE_WR(*gpuobj, 5, 0x00010000); + INSTANCE_WR(*gpuobj, 5, flags5); } (*gpuobj)->engine = NVOBJ_ENGINE_SW; @@ -700,6 +710,42 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, return 0; } +int +nouveau_gpuobj_gart_dma_new(struct drm_device *dev, int channel, + uint64_t offset, uint64_t size, int access, + struct nouveau_gpuobj **gpuobj, + uint32_t *o_ret) +{ + 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, + offset, size, access, + NV_DMA_TARGET_AGP, gpuobj); + if (o_ret) + *o_ret = 0; + } else + if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) { + *gpuobj = dev_priv->gart_info.sg_ctxdma; + if (offset & ~0xffffffffULL) { + DRM_ERROR("obj offset exceeds 32-bits\n"); + return DRM_ERR(EINVAL); + } + if (o_ret) + *o_ret = (uint32_t)offset; + ret = (*gpuobj != NULL) ? 0 : DRM_ERR(EINVAL); + } else { + DRM_ERROR("Invalid GART type %d\n", dev_priv->gart_info.type); + return DRM_ERR(EINVAL); + } + + return ret; +} + /* Context objects in the instance RAM have the following structure. * On NV40 they are 32 byte long, on NV30 and smaller 16 bytes. @@ -857,7 +903,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, 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; + int ret, i; DRM_DEBUG("ch%d vram=0x%08x tt=0x%08x\n", channel, vram_h, tt_h); @@ -870,6 +916,29 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, return ret; } + /* NV50 VM, point offset 0-512MiB at shared PCIEGART table */ + if (dev_priv->card_type >= NV_50) { + uint32_t vm_offset; + + 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, + 0, &chan->vm_pd, NULL))) + return ret; + for (i=0; i<0x4000; i+=8) { + INSTANCE_WR(chan->vm_pd, (i+0)/4, 0x00000000); + INSTANCE_WR(chan->vm_pd, (i+4)/4, 0xdeadcafe); + } + + if ((ret = nouveau_gpuobj_ref_add(dev, -1, 0, + dev_priv->gart_info.sg_ctxdma, + &chan->vm_gart_pt))) + return ret; + INSTANCE_WR(chan->vm_pd, (0+0)/4, + chan->vm_gart_pt->instance | 0x03); + INSTANCE_WR(chan->vm_pd, (0+4)/4, 0x00000000); + } + /* RAMHT */ if (dev_priv->card_type < NV_50) { ret = nouveau_gpuobj_ref_add(dev, -1, 0, dev_priv->ramht, @@ -899,40 +968,34 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, return ret; } - if (dev_priv->agp_heap) { - /* AGPGART ctxdma */ - if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, - 0, dev_priv->agp_available_size, - NV_DMA_ACCESS_RW, - NV_DMA_TARGET_AGP, &tt))) { - DRM_ERROR("Error creating AGP TT ctxdma: %d\n", DRM_ERR(ENOMEM)); - return DRM_ERR(ENOMEM); - } - - ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL); - if (ret) { - DRM_ERROR("Error referencing AGP TT 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, + 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, + 0, dev->sg->pages * PAGE_SIZE, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_PCI_NONLINEAR, &tt); + } else { + DRM_ERROR("Invalid GART type %d\n", dev_priv->gart_info.type); + ret = DRM_ERR(EINVAL); } - else if ( dev_priv->pci_heap) { - if (dev_priv -> card_type >= NV_50 ) return 0; /*no PCIGART for NV50*/ - /*PCI*/ - if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, - 0, dev->sg->pages * PAGE_SIZE, - NV_DMA_ACCESS_RW, - NV_DMA_TARGET_PCI_NONLINEAR, &tt))) { - DRM_ERROR("Error creating PCI TT ctxdma: %d\n", DRM_ERR(ENOMEM)); - return 0; //this is noncritical - } - - ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL); - if (ret) { - DRM_ERROR("Error referencing PCI TT ctxdma: %d\n", ret); - return ret; - } + if (ret) { + DRM_ERROR("Error creating TT ctxdma: %d\n", ret); + return ret; } + + ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL); + if (ret) { + DRM_ERROR("Error referencing TT ctxdma: %d\n", ret); + return ret; + } + return 0; } @@ -951,6 +1014,9 @@ nouveau_gpuobj_channel_takedown(struct drm_device *dev, int channel) } nouveau_gpuobj_ref_del(dev, &chan->ramht); + nouveau_gpuobj_del(dev, &chan->vm_pd); + nouveau_gpuobj_ref_del(dev, &chan->vm_gart_pt); + if (chan->ramin_heap) nouveau_mem_takedown(&chan->ramin_heap); if (chan->ramin) -- cgit v1.2.3 From e39286eb5eab8846a228863abf8f1b8b07a9e29d Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 19 Jul 2007 17:00:17 -0700 Subject: Remove DRM_ERR OS macro. This was used to make all ioctl handlers return -errno on linux and errno on *BSD. Instead, just return -errno in shared code, and flip sign on return from shared code to *BSD code. --- shared-core/nouveau_object.c | 58 ++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index f0025d7a..30d515f0 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -107,7 +107,7 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) if (!ramht) { DRM_ERROR("No hash table!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if (dev_priv->card_type < NV_40) { @@ -142,7 +142,7 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) } while (co != ho); DRM_ERROR("RAMHT space exhausted. ch=%d\n", ref->channel); - return DRM_ERR(ENOMEM); + return -ENOMEM; } static void @@ -194,17 +194,17 @@ nouveau_gpuobj_new(struct drm_device *dev, int channel, int size, int align, channel, size, align, flags); if (!dev_priv || !gpuobj_ret || *gpuobj_ret != NULL) - return DRM_ERR(EINVAL); + return -EINVAL; if (channel >= 0) { if (channel > nouveau_fifo_number(dev)) - return DRM_ERR(EINVAL); + return -EINVAL; chan = dev_priv->fifos[channel]; } gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER); if (!gpuobj) - return DRM_ERR(ENOMEM); + return -ENOMEM; DRM_DEBUG("gpuobj %p\n", gpuobj); gpuobj->flags = flags; gpuobj->im_channel = channel; @@ -230,7 +230,7 @@ nouveau_gpuobj_new(struct drm_device *dev, int channel, int size, int align, if (!pramin) { DRM_ERROR("No PRAMIN heap!\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if (!chan && (ret = engine->instmem.populate(dev, gpuobj, &size))) { @@ -244,7 +244,7 @@ nouveau_gpuobj_new(struct drm_device *dev, int channel, int size, int align, (DRMFILE)-2); if (!gpuobj->im_pramin) { nouveau_gpuobj_del(dev, &gpuobj); - return DRM_ERR(ENOMEM); + return -ENOMEM; } gpuobj->im_pramin->flags = NOUVEAU_MEM_INSTANCE; @@ -294,12 +294,12 @@ int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) DRM_DEBUG("gpuobj %p\n", pgpuobj ? *pgpuobj : NULL); if (!dev_priv || !pgpuobj || !(*pgpuobj)) - return DRM_ERR(EINVAL); + return -EINVAL; gpuobj = *pgpuobj; if (gpuobj->refcount != 0) { DRM_ERROR("gpuobj refcount is %d\n", gpuobj->refcount); - return DRM_ERR(EINVAL); + return -EINVAL; } engine->instmem.clear(dev, gpuobj); @@ -340,7 +340,7 @@ nouveau_gpuobj_instance_get(struct drm_device *dev, int channel, if ((channel > 0) && gpuobj->im_channel != channel) { DRM_ERROR("Channel mismatch: obj %d, ref %d\n", gpuobj->im_channel, channel); - return DRM_ERR(EINVAL); + return -EINVAL; } /* NV50 channel-local instance */ @@ -355,7 +355,7 @@ nouveau_gpuobj_instance_get(struct drm_device *dev, int channel, /* ...from global heap */ if (!gpuobj->im_backing) { DRM_ERROR("AII, no VRAM backing gpuobj\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } *inst = gpuobj->im_backing->start; return 0; @@ -367,7 +367,7 @@ nouveau_gpuobj_instance_get(struct drm_device *dev, int channel, return 0; } - return DRM_ERR(EINVAL); + return -EINVAL; } int @@ -383,15 +383,15 @@ nouveau_gpuobj_ref_add(struct drm_device *dev, int channel, uint32_t handle, DRM_DEBUG("ch%d h=0x%08x gpuobj=%p\n", channel, handle, gpuobj); if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL)) - return DRM_ERR(EINVAL); + return -EINVAL; if (channel >= 0) { if (channel > nouveau_fifo_number(dev)) - return DRM_ERR(EINVAL); + return -EINVAL; chan = dev_priv->fifos[channel]; } else if (!ref_ret) - return DRM_ERR(EINVAL); + return -EINVAL; ret = nouveau_gpuobj_instance_get(dev, channel, gpuobj, &instance); if (ret) @@ -399,7 +399,7 @@ nouveau_gpuobj_ref_add(struct drm_device *dev, int channel, uint32_t handle, ref = drm_calloc(1, sizeof(*ref), DRM_MEM_DRIVER); if (!ref) - return DRM_ERR(ENOMEM); + return -ENOMEM; ref->gpuobj = gpuobj; ref->channel = channel; ref->instance = instance; @@ -431,7 +431,7 @@ int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **p DRM_DEBUG("ref %p\n", pref ? *pref : NULL); if (!dev || !pref || *pref == NULL) - return DRM_ERR(EINVAL); + return -EINVAL; ref = *pref; if (ref->handle != ~0) @@ -487,7 +487,7 @@ nouveau_gpuobj_ref_find(struct drm_device *dev, int channel, uint32_t handle, ref = ref->next; } - return DRM_ERR(EINVAL); + return -EINVAL; } int @@ -504,7 +504,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size, gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER); if (!gpuobj) - return DRM_ERR(ENOMEM); + return -ENOMEM; DRM_DEBUG("gpuobj %p\n", gpuobj); gpuobj->im_channel = -1; gpuobj->flags = flags | NVOBJ_FLAG_FAKE; @@ -513,7 +513,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size, DRM_MEM_DRIVER); if (!gpuobj->im_pramin) { nouveau_gpuobj_del(dev, &gpuobj); - return DRM_ERR(ENOMEM); + return -ENOMEM; } gpuobj->im_pramin->start = offset; gpuobj->im_pramin->size = size; @@ -650,7 +650,7 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, if ((idx + page_count) > dev->sg->pages) { DRM_ERROR("Requested page range exceedes " "allocated scatter-gather range!"); - return DRM_ERR(E2BIG); + return -E2BIG; } DRM_DEBUG("Creating PCI DMA object using virtual zone starting at %#llx, size %d\n", offset, (uint32_t)size); @@ -676,7 +676,7 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev->sg->busaddr[idx])) { - return DRM_ERR(ENOMEM); + return -ENOMEM; } } @@ -733,14 +733,14 @@ nouveau_gpuobj_gart_dma_new(struct drm_device *dev, int channel, *gpuobj = dev_priv->gart_info.sg_ctxdma; if (offset & ~0xffffffffULL) { DRM_ERROR("obj offset exceeds 32-bits\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } if (o_ret) *o_ret = (uint32_t)offset; - ret = (*gpuobj != NULL) ? 0 : DRM_ERR(EINVAL); + ret = (*gpuobj != NULL) ? 0 : -EINVAL; } else { DRM_ERROR("Invalid GART type %d\n", dev_priv->gart_info.type); - return DRM_ERR(EINVAL); + return -EINVAL; } return ret; @@ -982,7 +982,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, NV_DMA_TARGET_PCI_NONLINEAR, &tt); } else { DRM_ERROR("Invalid GART type %d\n", dev_priv->gart_info.type); - ret = DRM_ERR(EINVAL); + ret = -EINVAL; } if (ret) { @@ -1038,15 +1038,15 @@ int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) 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); + return -EINVAL; } //FIXME: check args, only allow trusted objects to be created if (init.handle == ~0) - return DRM_ERR(EINVAL); + return -EINVAL; if (nouveau_gpuobj_ref_find(dev, init.channel, init.handle, NULL) == 0) - return DRM_ERR(EEXIST); + return -EEXIST; if ((ret = nouveau_gpuobj_gr_new(dev, init.channel, init.class, &gr))) { DRM_ERROR("Error creating gr object: %d (%d/0x%08x)\n", -- cgit v1.2.3 From c1119b1b092527fbb6950d0b5e51e076ddb00f29 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 20 Jul 2007 06:39:25 -0700 Subject: Replace filp in ioctl arguments with drm_file *file_priv. As a fallout, replace filp storage with file_priv storage for "unique identifier of a client" all over the DRM. There is a 1:1 mapping, so this should be a noop. This could be a minor performance improvement, as everything on Linux dereferenced filp to get file_priv anyway, while only the mmap ioctls went the other direction. --- shared-core/nouveau_object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 30d515f0..f11cc115 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -241,7 +241,7 @@ nouveau_gpuobj_new(struct drm_device *dev, int channel, int size, int align, /* Allocate a chunk of the PRAMIN aperture */ gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size, drm_order(align), - (DRMFILE)-2); + (struct drm_file *)-2); if (!gpuobj->im_pramin) { nouveau_gpuobj_del(dev, &gpuobj); return -ENOMEM; @@ -1035,7 +1035,7 @@ int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) (struct drm_nouveau_grobj_alloc_t __user*)data, sizeof(init)); - if (!nouveau_fifo_owner(dev, filp, init.channel)) { + 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; -- cgit v1.2.3 From 5b38e134163cc375e91424c4688cc9328c6e9082 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 19 Jul 2007 17:11:11 -0700 Subject: Replace DRM_IOCTL_ARGS with (dev, data, file_priv) and remove DRM_DEVICE. The data is now in kernel space, copied in/out as appropriate according to the This results in DRM_COPY_{TO,FROM}_USER going away, and error paths to deal with those failures. This also means that XFree86 4.2.0 support for i810 DRM is lost. --- shared-core/nouveau_object.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index f11cc115..e8b12bb7 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -1024,40 +1024,37 @@ nouveau_gpuobj_channel_takedown(struct drm_device *dev, int channel) } -int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) +int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { - DRM_DEVICE; - struct drm_nouveau_grobj_alloc init; + struct drm_nouveau_grobj_alloc *init = data; struct nouveau_gpuobj *gr = NULL; int ret; - DRM_COPY_FROM_USER_IOCTL(init, - (struct drm_nouveau_grobj_alloc_t __user*)data, - sizeof(init)); - - if (!nouveau_fifo_owner(dev, file_priv, init.channel)) { + if (!nouveau_fifo_owner(dev, file_priv, init->channel)) { DRM_ERROR("pid %d doesn't own channel %d\n", - DRM_CURRENTPID, init.channel); + DRM_CURRENTPID, init->channel); return -EINVAL; } //FIXME: check args, only allow trusted objects to be created - if (init.handle == ~0) + if (init->handle == ~0) return -EINVAL; - if (nouveau_gpuobj_ref_find(dev, init.channel, init.handle, NULL) == 0) + if (nouveau_gpuobj_ref_find(dev, init->channel, init->handle, NULL) == + 0) return -EEXIST; - if ((ret = nouveau_gpuobj_gr_new(dev, init.channel, init.class, &gr))) { + ret = nouveau_gpuobj_gr_new(dev, init->channel, init->class, &gr); + if (ret) { DRM_ERROR("Error creating gr object: %d (%d/0x%08x)\n", - ret, init.channel, init.handle); + ret, init->channel, init->handle); return ret; } - if ((ret = nouveau_gpuobj_ref_add(dev, init.channel, init.handle, + if ((ret = nouveau_gpuobj_ref_add(dev, init->channel, init->handle, gr, NULL))) { DRM_ERROR("Error referencing gr object: %d (%d/0x%08x\n)", - ret, init.channel, init.handle); + ret, init->channel, init->handle); nouveau_gpuobj_del(dev, &gr); return ret; } -- cgit v1.2.3 From beaa0c9a28b30a6ba3292184d04875b6a597e433 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 6 Aug 2007 03:40:43 +1000 Subject: nouveau: Pass channel struct around instead of channel id. --- shared-core/nouveau_object.c | 150 ++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 81 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index e8b12bb7..274bb2a7 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -100,7 +100,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; @@ -149,7 +149,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; @@ -180,34 +180,28 @@ 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; /* Choose between global instmem heap, and per-channel private * instmem heap. On 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); @@ -325,7 +319,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 +332,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 +366,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 +392,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) { @@ -452,8 +443,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; @@ -471,11 +463,9 @@ nouveau_gpuobj_new_ref(struct drm_device *dev, int oc, int rc, uint32_t handle, } static int -nouveau_gpuobj_ref_find(struct drm_device *dev, int channel, uint32_t handle, +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; while (ref) { @@ -524,7 +514,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 +567,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 +582,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 +599,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 +702,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 +789,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 +839,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 +868,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 +889,21 @@ 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); + 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 card_type == NV_50) { - ret = nouveau_gpuobj_channel_init_pramin(dev, channel); + ret = nouveau_gpuobj_channel_init_pramin(chan); if (ret) return ret; } @@ -930,7 +922,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 +933,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 +947,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 +955,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 +981,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,13 +991,12 @@ 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 nouveau_gpuobj_ref *ref; - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); while ((ref = chan->ramht_refs)) { chan->ramht_refs = ref->next; @@ -1024,35 +1014,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_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) == + + 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); -- cgit v1.2.3 From 97770db72040dc032130413e0cdabc1777560a75 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 6 Aug 2007 21:45:18 +1000 Subject: 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. --- shared-core/nouveau_object.c | 99 +++++++++++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 25 deletions(-) (limited to 'shared-core/nouveau_object.c') 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 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; +} + -- cgit v1.2.3 From 66f5232d9393f6886d8fd1a60b2d75cd009b972c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 7 Aug 2007 01:51:46 +1000 Subject: nouveau: Init global gpuobj list early, unbreaks sgdma code. --- shared-core/nouveau_object.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 22ad23cd..bb096531 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -270,8 +270,6 @@ 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, -- cgit v1.2.3 From 39907f613b6c84499c34c9a6ece5f5dde64788c0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 10 Aug 2007 13:53:10 +1000 Subject: nouveau: Allow creation of gpuobjs before any other init has taken place. --- shared-core/nouveau_object.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index bb096531..d4142e44 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -264,12 +264,26 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, 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, dev_priv->ramht_size, @@ -286,12 +300,20 @@ 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"); 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"); list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) { gpuobj = list_entry(entry, struct nouveau_gpuobj, list); -- cgit v1.2.3 From a46104674f129e873b8dfa29cf8aac9c67bd77be Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 10 Aug 2007 13:54:26 +1000 Subject: nouveau/nv50: demagic instmem setup. --- shared-core/nouveau_object.c | 50 +++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 14 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index d4142e44..e0cb334f 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; } @@ -286,7 +288,7 @@ nouveau_gpuobj_init(struct drm_device *dev) if (dev_priv->card_type < NV_50) { if ((ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset, - dev_priv->ramht_size, + ~0, dev_priv->ramht_size, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ALLOW_NO_REFS, &dev_priv->ramht, NULL))) @@ -346,7 +348,13 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) if (gpuobj->dtor) gpuobj->dtor(dev, gpuobj); - engine->instmem.clear(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) @@ -525,7 +533,8 @@ nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle, } 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) { @@ -533,8 +542,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) @@ -545,14 +554,27 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size, 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) { - nouveau_gpuobj_del(dev, &gpuobj); - return -ENOMEM; + 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) @@ -962,7 +984,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, 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) { -- cgit v1.2.3 From 8645dac8952473dc3e09ba7a7a9db3fbdf75215f Mon Sep 17 00:00:00 2001 From: Matthieu Castet Date: Wed, 22 Aug 2007 23:17:56 +0200 Subject: nouveau : fix some potential crashes with objects causing hash collision --- shared-core/nouveau_object.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index e0cb334f..fbce7702 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -141,8 +141,13 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) 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); -- cgit v1.2.3