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. --- linux-core/Makefile.kernel | 2 +- linux-core/nouveau_notifier.c | 1 + shared-core/nouveau_drm.h | 28 ++++---- shared-core/nouveau_drv.h | 28 +++++++- shared-core/nouveau_fifo.c | 45 +++++++++--- shared-core/nouveau_mem.c | 51 +++++++++----- shared-core/nouveau_notifier.c | 154 +++++++++++++++++++++++++++++++++++++++++ shared-core/nouveau_object.c | 143 +++++++++++++------------------------- shared-core/nouveau_state.c | 3 +- 9 files changed, 315 insertions(+), 140 deletions(-) create mode 120000 linux-core/nouveau_notifier.c create mode 100644 shared-core/nouveau_notifier.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 9427a04b..6ab17a49 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -21,7 +21,7 @@ i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ i915_buffer.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ - nouveau_object.o nouveau_irq.o \ + nouveau_object.o nouveau_irq.o nouveau_notifier.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o \ nv04_fb.o nv10_fb.o nv40_fb.o \ diff --git a/linux-core/nouveau_notifier.c b/linux-core/nouveau_notifier.c new file mode 120000 index 00000000..285469c5 --- /dev/null +++ b/linux-core/nouveau_notifier.c @@ -0,0 +1 @@ +../shared-core/nouveau_notifier.c \ No newline at end of file diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index 1e7322e0..0758991a 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -25,9 +25,12 @@ #ifndef __NOUVEAU_DRM_H__ #define __NOUVEAU_DRM_H__ -#define NOUVEAU_DRM_HEADER_PATCHLEVEL 6 +#define NOUVEAU_DRM_HEADER_PATCHLEVEL 7 typedef struct drm_nouveau_fifo_alloc { + uint32_t fb_ctxdma_handle; + uint32_t tt_ctxdma_handle; + int channel; uint32_t put_base; /* FIFO control regs */ @@ -36,29 +39,30 @@ typedef struct drm_nouveau_fifo_alloc { /* DMA command buffer */ drm_handle_t cmdbuf; int cmdbuf_size; + /* Notifier memory */ + drm_handle_t notifier; + int notifier_size; } drm_nouveau_fifo_alloc_t; -typedef struct drm_nouveau_object_init { +typedef struct drm_nouveau_grobj_alloc { int channel; uint32_t handle; int class; } -drm_nouveau_object_init_t; +drm_nouveau_grobj_alloc_t; #define NOUVEAU_MEM_ACCESS_RO 1 #define NOUVEAU_MEM_ACCESS_WO 2 #define NOUVEAU_MEM_ACCESS_RW 3 -typedef struct drm_nouveau_dma_object_init { +typedef struct drm_nouveau_notifier_alloc { int channel; uint32_t handle; - int class; - int access; - int target; + int count; + uint32_t offset; - int size; } -drm_nouveau_dma_object_init_t; +drm_nouveau_notifier_alloc_t; #define NOUVEAU_MEM_FB 0x00000001 #define NOUVEAU_MEM_AGP 0x00000002 @@ -68,7 +72,7 @@ drm_nouveau_dma_object_init_t; #define NOUVEAU_MEM_USER_BACKED 0x00000020 #define NOUVEAU_MEM_MAPPED 0x00000040 #define NOUVEAU_MEM_INSTANCE 0x00000080 /* internal */ - +#define NOUVEAU_MEM_NOTIFIER 0x00000100 /* internal */ typedef struct drm_nouveau_mem_alloc { int flags; int alignment; @@ -141,8 +145,8 @@ typedef struct drm_nouveau_sarea { drm_nouveau_sarea_t; #define DRM_NOUVEAU_FIFO_ALLOC 0x00 -#define DRM_NOUVEAU_OBJECT_INIT 0x01 -#define DRM_NOUVEAU_DMA_OBJECT_INIT 0x02 +#define DRM_NOUVEAU_GROBJ_ALLOC 0x01 +#define DRM_NOUVEAU_NOTIFIER_ALLOC 0x02 #define DRM_NOUVEAU_MEM_ALLOC 0x03 #define DRM_NOUVEAU_MEM_FREE 0x04 #define DRM_NOUVEAU_GETPARAM 0x05 diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index b3122d8a..7a1ca3d5 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -34,7 +34,7 @@ #define DRIVER_MAJOR 0 #define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 6 +#define DRIVER_PATCHLEVEL 7 #define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FLAGS 0xFFFF0000 @@ -84,6 +84,10 @@ struct nouveau_fifo struct mem_block *cmdbuf_mem; struct nouveau_object *cmdbuf_obj; uint32_t pushbuf_base; + /* notifier memory */ + struct mem_block *notifier_block; + struct mem_block *notifier_heap; + drm_local_map_t *notifier_map; /* PGRAPH context, for cards that keep it in RAMIN */ struct mem_block *ramin_grctx; /* objects belonging to this fifo */ @@ -197,6 +201,12 @@ extern void nouveau_wait_for_idle(struct drm_device *dev); extern int nouveau_ioctl_card_init(DRM_IOCTL_ARGS); /* nouveau_mem.c */ +extern int nouveau_mem_init_heap(struct mem_block **, + uint64_t start, uint64_t size); +extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, + uint64_t size, int align2, + DRMFILE); +extern void nouveau_mem_free_block(struct mem_block *); extern uint64_t nouveau_mem_fb_amount(struct drm_device *dev); extern void nouveau_mem_release(DRMFILE filp, struct mem_block *heap); extern int nouveau_ioctl_mem_alloc(DRM_IOCTL_ARGS); @@ -216,6 +226,13 @@ extern void nouveau_instmem_w32(drm_nouveau_private_t *dev_priv, struct mem_block *mem, int index, uint32_t val); +/* nouveau_notifier.c */ +extern int nouveau_notifier_init_channel(drm_device_t *, int channel, DRMFILE); +extern void nouveau_notifier_takedown_channel(drm_device_t *, int channel); +extern int nouveau_notifier_alloc(drm_device_t *, int channel, + uint32_t handle, int cout, uint32_t *offset); +extern int nouveau_ioctl_notifier_alloc(DRM_IOCTL_ARGS); + /* nouveau_fifo.c */ extern int nouveau_fifo_init(drm_device_t *dev); extern int nouveau_fifo_number(drm_device_t *dev); @@ -225,7 +242,13 @@ extern int nouveau_fifo_owner(drm_device_t *dev, DRMFILE filp, int channel); extern void nouveau_fifo_free(drm_device_t *dev, int channel); /* nouveau_object.c */ +extern int nouveau_object_init_channel(drm_device_t *, int channel, + uint32_t vram_handle, + uint32_t tt_handle); +extern void nouveau_object_takedown_channel(drm_device_t *dev, int channel); extern void nouveau_object_cleanup(drm_device_t *dev, int channel); +extern int nouveau_ht_object_insert(drm_device_t *, int channel, + uint32_t handle, struct nouveau_object *); extern struct nouveau_object * nouveau_object_gr_create(drm_device_t *dev, int channel, int class); extern struct nouveau_object * @@ -233,8 +256,7 @@ nouveau_object_dma_create(drm_device_t *dev, int channel, int class, uint32_t offset, uint32_t size, int access, int target); extern void nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj); -extern int nouveau_ioctl_object_init(DRM_IOCTL_ARGS); -extern int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS); +extern int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS); extern uint32_t nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem); /* nouveau_irq.c */ diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 1a06f913..f179af63 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -241,7 +241,8 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) } /* allocates and initializes a fifo for user space consumption */ -static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) +int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp, + uint32_t vram_handle, uint32_t tt_handle) { int ret; drm_nouveau_private_t *dev_priv = dev->dev_private; @@ -282,6 +283,20 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) return ret; } + /* Setup channel's default objects */ + ret = nouveau_object_init_channel(dev, channel, vram_handle, tt_handle); + if (ret) { + nouveau_fifo_free(dev, channel); + return ret; + } + + /* Allocate space for per-channel fixed notifier memory */ + ret = nouveau_notifier_init_channel(dev, channel, filp); + if (ret) { + nouveau_fifo_free(dev, channel); + return ret; + } + nouveau_wait_for_idle(dev); /* disable the fifo caches */ @@ -370,6 +385,8 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) if (chan->cmdbuf_mem) nouveau_mem_free(dev, chan->cmdbuf_mem); + nouveau_notifier_takedown_channel(dev, channel); + /* Destroy objects belonging to the channel */ nouveau_object_cleanup(dev, channel); @@ -408,30 +425,42 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan; drm_nouveau_fifo_alloc_t init; int res; DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_fifo_alloc_t __user *) data, sizeof(init)); - res = nouveau_fifo_alloc(dev, &init.channel, filp); + res = nouveau_fifo_alloc(dev, &init.channel, filp, + init.fb_ctxdma_handle, + init.tt_ctxdma_handle); if (res) return res; + chan = &dev_priv->fifos[init.channel]; - init.put_base = dev_priv->fifos[init.channel].pushbuf_base; + init.put_base = chan->pushbuf_base; /* make the fifo available to user space */ /* first, the fifo control regs */ init.ctrl = dev_priv->mmio->offset + NV03_FIFO_REGS(init.channel); init.ctrl_size = NV03_FIFO_REGS_SIZE; res = drm_addmap(dev, init.ctrl, init.ctrl_size, _DRM_REGISTERS, - 0, &dev_priv->fifos[init.channel].regs); + 0, &chan->regs); if (res != 0) return res; /* pass back FIFO map info to the caller */ - init.cmdbuf = dev_priv->fifos[init.channel].cmdbuf_mem->start; - init.cmdbuf_size = dev_priv->fifos[init.channel].cmdbuf_mem->size; + init.cmdbuf = chan->cmdbuf_mem->start; + init.cmdbuf_size = chan->cmdbuf_mem->size; + + /* and the notifier block */ + init.notifier = chan->notifier_block->start; + init.notifier_size = chan->notifier_block->size; + res = drm_addmap(dev, init.notifier, init.notifier_size, _DRM_REGISTERS, + 0, &chan->notifier_map); + if (res != 0) + return res; DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_alloc_t __user *)data, init, sizeof(init)); @@ -444,8 +473,8 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS) drm_ioctl_desc_t nouveau_ioctls[] = { [DRM_IOCTL_NR(DRM_NOUVEAU_FIFO_ALLOC)] = {nouveau_ioctl_fifo_alloc, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_NOUVEAU_OBJECT_INIT)] = {nouveau_ioctl_object_init, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_NOUVEAU_DMA_OBJECT_INIT)] = {nouveau_ioctl_dma_object_init, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_NOUVEAU_GROBJ_ALLOC)] = {nouveau_ioctl_grobj_alloc, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_NOUVEAU_NOTIFIER_ALLOC)] = {nouveau_ioctl_notifier_alloc, DRM_AUTH}, [DRM_IOCTL_NR(DRM_NOUVEAU_MEM_ALLOC)] = {nouveau_ioctl_mem_alloc, DRM_AUTH}, [DRM_IOCTL_NR(DRM_NOUVEAU_MEM_FREE)] = {nouveau_ioctl_mem_free, DRM_AUTH}, [DRM_IOCTL_NR(DRM_NOUVEAU_GETPARAM)] = {nouveau_ioctl_getparam, DRM_AUTH}, diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index a5343b99..edfc9d3f 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -77,8 +77,8 @@ out: return p; } -static struct mem_block *alloc_block(struct mem_block *heap, uint64_t size, - int align2, DRMFILE filp) +struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size, + int align2, DRMFILE filp) { struct mem_block *p; uint64_t mask = (1 << align2) - 1; @@ -106,7 +106,7 @@ static struct mem_block *find_block(struct mem_block *heap, uint64_t start) return NULL; } -static void free_block(struct mem_block *p) +void nouveau_mem_free_block(struct mem_block *p) { p->filp = NULL; @@ -132,7 +132,8 @@ static void free_block(struct mem_block *p) /* Initialize. How to check for an uninitialized heap? */ -static int init_heap(struct mem_block **heap, uint64_t start, uint64_t size) +int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start, + uint64_t size) { struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS); @@ -331,7 +332,9 @@ int nouveau_mem_init(struct drm_device *dev) goto no_agp; } - if (init_heap(&dev_priv->agp_heap, info.aperture_base, info.aperture_size)) + if (nouveau_mem_init_heap(&dev_priv->agp_heap, + info.aperture_base, + info.aperture_size)) goto no_agp; dev_priv->agp_phys = info.aperture_base; @@ -357,12 +360,19 @@ no_agp: if (fb_size>256*1024*1024) { /* On cards with > 256Mb, you can't map everything. * So we create a second FB heap for that type of memory */ - if (init_heap(&dev_priv->fb_heap, drm_get_resource_start(dev,1), 256*1024*1024)) + if (nouveau_mem_init_heap(&dev_priv->fb_heap, + drm_get_resource_start(dev,1), + 256*1024*1024)) return DRM_ERR(ENOMEM); - if (init_heap(&dev_priv->fb_nomap_heap, drm_get_resource_start(dev,1)+256*1024*1024, fb_size-256*1024*1024)) + if (nouveau_mem_init_heap(&dev_priv->fb_nomap_heap, + drm_get_resource_start(dev,1) + + 256*1024*1024, + fb_size-256*1024*1024)) return DRM_ERR(ENOMEM); } else { - if (init_heap(&dev_priv->fb_heap, drm_get_resource_start(dev,1), fb_size)) + if (nouveau_mem_init_heap(&dev_priv->fb_heap, + drm_get_resource_start(dev,1), + fb_size)) return DRM_ERR(ENOMEM); dev_priv->fb_nomap_heap=NULL; } @@ -397,21 +407,25 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, uint6 if (flags&NOUVEAU_MEM_AGP) { type=NOUVEAU_MEM_AGP; - block = alloc_block(dev_priv->agp_heap, size, alignment, filp); + block = nouveau_mem_alloc_block(dev_priv->agp_heap, size, + alignment, filp); if (block) goto alloc_ok; } if (flags&(NOUVEAU_MEM_FB|NOUVEAU_MEM_FB_ACCEPTABLE)) { type=NOUVEAU_MEM_FB; if (!(flags&NOUVEAU_MEM_MAPPED)) { - block = alloc_block(dev_priv->fb_nomap_heap, size, alignment, filp); + block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap, + size, alignment, filp); if (block) goto alloc_ok; } - block = alloc_block(dev_priv->fb_heap, size, alignment, filp); + block = nouveau_mem_alloc_block(dev_priv->fb_heap, size, + alignment, filp); if (block) goto alloc_ok; } if (flags&NOUVEAU_MEM_AGP_ACCEPTABLE) { type=NOUVEAU_MEM_AGP; - block = alloc_block(dev_priv->agp_heap, size, alignment, filp); + block = nouveau_mem_alloc_block(dev_priv->agp_heap, size, + alignment, filp); if (block) goto alloc_ok; } @@ -432,7 +446,7 @@ alloc_ok: ret = drm_addmap(dev, block->start, block->size, _DRM_FRAME_BUFFER, 0, &block->map); if (ret) { - free_block(block); + nouveau_mem_free_block(block); return NULL; } } @@ -446,7 +460,7 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) DRM_INFO("freeing 0x%llx\n", block->start); if (block->flags&NOUVEAU_MEM_MAPPED) drm_rmmap(dev, block->map); - free_block(block); + nouveau_mem_free_block(block); } static void @@ -549,8 +563,8 @@ int nouveau_instmem_init(struct drm_device *dev) * the space that was reserved for RAMHT/FC/RO. */ offset = dev_priv->ramfc_offset + dev_priv->ramfc_size; - ret = init_heap(&dev_priv->ramin_heap, - offset, dev_priv->ramin_size - offset); + ret = nouveau_mem_init_heap(&dev_priv->ramin_heap, + offset, dev_priv->ramin_size - offset); if (ret) { dev_priv->ramin_heap = NULL; DRM_ERROR("Failed to init RAMIN heap\n"); @@ -570,7 +584,8 @@ struct mem_block *nouveau_instmem_alloc(struct drm_device *dev, return NULL; } - block = alloc_block(dev_priv->ramin_heap, size, align, (DRMFILE)-2); + block = nouveau_mem_alloc_block(dev_priv->ramin_heap, size, align, + (DRMFILE)-2); if (block) { block->flags = NOUVEAU_MEM_INSTANCE; DRM_DEBUG("instance(size=%d, align=%d) alloc'd at 0x%08x\n", @@ -583,7 +598,7 @@ struct mem_block *nouveau_instmem_alloc(struct drm_device *dev, void nouveau_instmem_free(struct drm_device *dev, struct mem_block *block) { if (dev && block) { - free_block(block); + nouveau_mem_free_block(block); } } diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c new file mode 100644 index 00000000..ab6f8c2d --- /dev/null +++ b/shared-core/nouveau_notifier.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +int +nouveau_notifier_init_channel(drm_device_t *dev, int channel, DRMFILE filp) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + int flags, ret; + + /*TODO: PCI notifier blocks */ + if (dev_priv->agp_heap) + flags = NOUVEAU_MEM_AGP | NOUVEAU_MEM_FB_ACCEPTABLE; + else + flags = NOUVEAU_MEM_FB; + + chan->notifier_block = nouveau_mem_alloc(dev, 0, PAGE_SIZE, flags,filp); + if (!chan->notifier_block) + return DRM_ERR(ENOMEM); + + ret = nouveau_mem_init_heap(&chan->notifier_heap, + 0, chan->notifier_block->size); + if (ret) + return ret; + + return 0; +} + +void +nouveau_notifier_takedown_channel(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + + if (chan->notifier_block) { + nouveau_mem_free(dev, chan->notifier_block); + chan->notifier_block = NULL; + } + + /*XXX: heap destroy */ +} + +int +nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, + int count, uint32_t *b_offset) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_object *obj; + struct mem_block *mem; + uint32_t offset; + int target; + + if (!chan->notifier_heap) { + DRM_ERROR("Channel %d doesn't have a notifier heap!\n", + channel); + return DRM_ERR(EINVAL); + } + + mem = nouveau_mem_alloc_block(chan->notifier_heap, 32, 0, chan->filp); + if (!mem) { + DRM_ERROR("Channel %d notifier block full\n", channel); + return DRM_ERR(ENOMEM); + } + mem->flags = NOUVEAU_MEM_NOTIFIER; + + offset = chan->notifier_block->start + mem->start; + if (chan->notifier_block->flags & NOUVEAU_MEM_FB) { + offset -= drm_get_resource_start(dev, 1); + target = NV_DMA_TARGET_VIDMEM; + } else if (chan->notifier_block->flags & NOUVEAU_MEM_AGP) { + offset -= dev_priv->agp_phys; + target = NV_DMA_TARGET_AGP; + } else { + DRM_ERROR("Bad DMA target, flags 0x%08x!\n", + chan->notifier_block->flags); + return DRM_ERR(EINVAL); + } + + obj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, + offset, mem->size, NV_DMA_ACCESS_RW, + target); + if (!obj) { + nouveau_mem_free_block(mem); + DRM_ERROR("Error creating notifier ctxdma\n"); + return DRM_ERR(ENOMEM); + } + + obj->handle = handle; + if (nouveau_ht_object_insert(dev, channel, handle, obj)) { + nouveau_object_free(dev, obj); + nouveau_mem_free_block(mem); + DRM_ERROR("Error inserting notifier ctxdma into RAMHT\n"); + return DRM_ERR(ENOMEM); + } + + *b_offset = mem->start; + return 0; +} + +int +nouveau_ioctl_notifier_alloc(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_nouveau_notifier_alloc_t na; + int ret; + + DRM_COPY_FROM_USER_IOCTL(na, (drm_nouveau_notifier_alloc_t __user*)data, + sizeof(na)); + + if (!nouveau_fifo_owner(dev, filp, na.channel)) { + DRM_ERROR("pid %d doesn't own channel %d\n", + DRM_CURRENTPID, na.channel); + return DRM_ERR(EPERM); + } + + ret = nouveau_notifier_alloc(dev, na.channel, na.handle, + na.count, &na.offset); + if (ret) + return ret; + + DRM_COPY_TO_USER_IOCTL((drm_nouveau_notifier_alloc_t __user*)data, + na, sizeof(na)); + return 0; +} + 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); diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index b3562e2f..68392c3a 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -260,9 +260,9 @@ void nouveau_preclose(drm_device_t * dev, DRMFILE filp) { drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_fifo_cleanup(dev, filp); nouveau_mem_release(filp,dev_priv->fb_heap); nouveau_mem_release(filp,dev_priv->agp_heap); - nouveau_fifo_cleanup(dev, filp); } /* first module load, setup the mmio/fb mapping */ @@ -282,7 +282,6 @@ int nouveau_firstopen(struct drm_device *dev) int nouveau_load(struct drm_device *dev, unsigned long flags) { drm_nouveau_private_t *dev_priv; - int ret; if (flags==NV_UNKNOWN) return DRM_ERR(EINVAL); -- cgit v1.2.3