diff options
author | Alan Hourihane <alanh@fairlite.demon.co.uk> | 2007-06-29 20:09:44 +0100 |
---|---|---|
committer | Alan Hourihane <alanh@fairlite.demon.co.uk> | 2007-06-29 20:09:44 +0100 |
commit | 8a78dead291ffdb5a8774419cdca369a1e27cad9 (patch) | |
tree | 399b8378e32036bdc7dadc10c639465a8fb21681 /shared-core/nouveau_object.c | |
parent | e79e2a58161d44754fd55507e155b7e12a09c4d2 (diff) | |
parent | a27af4c4a665864df09123f177ca7269e48f6171 (diff) |
Merge branch 'master' of git+ssh://git.freedesktop.org/git/mesa/drm into modesetting-101
Conflicts:
linux-core/drm_drv.c
linux-core/drm_fops.c
linux-core/drm_objects.h
linux-core/drm_stub.c
shared-core/i915_dma.c
Diffstat (limited to 'shared-core/nouveau_object.c')
-rw-r--r-- | shared-core/nouveau_object.c | 268 |
1 files changed, 123 insertions, 145 deletions
diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index ace7c2aa..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; @@ -154,62 +154,89 @@ nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle) } static int -nouveau_ht_object_insert(drm_device_t* dev, int channel, uint32_t handle, - struct nouveau_object *obj) +nouveau_ramht_entry_valid(drm_device_t *dev, uint32_t ramht, uint32_t offset) { 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 == ht_end) ofs = ht_base; - if (ofs == o_ofs) { - DRM_ERROR("no free hash table entries\n"); - return 1; - } + 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_ramht_insert(drm_device_t* dev, int channel, uint32_t handle, + struct nouveau_object *obj) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + 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,119 +484,74 @@ 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); } -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_ramht_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_ramht_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 +560,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,14 +568,11 @@ 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)) { + if (nouveau_ramht_insert(dev, init.channel, init.handle, obj)) { nouveau_object_free(dev, obj); return DRM_ERR(ENOMEM); } |