From fef9b30a2b437c0103c33443566604027529b91d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 27 Aug 2006 08:55:02 +1000 Subject: initial import of nouveau code from nouveau CVS --- shared-core/nouveau_object.c | 565 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 shared-core/nouveau_object.c (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c new file mode 100644 index 00000000..fb30d529 --- /dev/null +++ b/shared-core/nouveau_object.c @@ -0,0 +1,565 @@ +#include "drmP.h" +#include "drm.h" +#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. + */ + +static void nouveau_object_link(drm_device_t *dev, int fifo_num, + struct nouveau_object *obj) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + struct nouveau_fifo *fifo = &dev_priv->fifos[fifo_num]; + + if (!fifo->objs) { + fifo->objs = obj; + return; + } + + obj->prev = NULL; + obj->next = fifo->objs; + + fifo->objs->prev = obj; + fifo->objs = obj; +} + +static void nouveau_object_unlink(drm_device_t *dev, int fifo_num, + struct nouveau_object *obj) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + struct nouveau_fifo *fifo = &dev_priv->fifos[fifo_num]; + + if (obj->prev == NULL) { + if (obj->next) + obj->next->prev = NULL; + fifo->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 fifo_num, uint32_t handle) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + struct nouveau_fifo *fifo = &dev_priv->fifos[fifo_num]; + struct nouveau_object *obj = fifo->objs; + + if (!handle) + return NULL; + + 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, + and then used via DMA command buffers. + + A context object is referenced by a user defined handle (CARD32). The HW + looks up graphics objects in a hash table in the instance RAM. + + An entry in the hash table consists of 2 CARD32. The first CARD32 contains + the handle, the second one a bitfield, that contains the address of the + object in instance RAM. + + The format of the second CARD32 seems to be: + + NV4 to NV30: + + 15: 0 instance_addr >> 4 + 17:16 engine (here uses 1 = graphics) + 28:24 channel id (here uses 0) + 31 valid (use 1) + + NV40: + + 15: 0 instance_addr >> 4 (maybe 19-0) + 21:20 engine (here uses 1 = graphics) + I'm unsure about the other bits, but using 0 seems to work. + + The key into the hash table depends on the object handle and channel id and + is given as: +*/ +static uint32_t nouveau_handle_hash(drm_device_t* dev, uint32_t handle, + int fifo) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + struct nouveau_object_store *objs=&dev_priv->objs; + uint32_t hash = 0; + int i; + + for (i=32;i>0;i-=objs->ht_bits) { + hash ^= (handle & ((1 << objs->ht_bits) - 1)); + handle >>= objs->ht_bits; + } + hash ^= fifo << (objs->ht_bits - 4); + return hash << 3; +} + +static int nouveau_hash_table_insert(drm_device_t* dev, int fifo, + struct nouveau_object *obj) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + struct nouveau_object_store *objs=&dev_priv->objs; + int ht_base = NV_RAMIN + objs->ht_base; + int ht_end = ht_base + objs->ht_size; + int o_ofs, ofs; + + o_ofs = ofs = nouveau_handle_hash(dev, obj->handle, fifo); + + while (NV_READ(ht_base + ofs)) { + ofs += 8; + if (ofs == ht_end) ofs = ht_base; + if (ofs == o_ofs) { + DRM_ERROR("no free hash table entries\n"); + return 1; + } + } + ofs += ht_base; + + DRM_DEBUG("Channel %d - Handle 0x%08x at 0x%08x\n", + fifo, 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, + (fifo << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | + (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT) | + (obj->instance>>4) + ); + else + NV_WRITE(NV_RAMHT_CONTEXT_OFFSET + ofs, + NV_RAMHT_CONTEXT_VALID | + (fifo << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | + (obj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT) | + (obj->instance>>4) + ); + + obj->ht_loc = ofs; + return 0; +} + +static void nouveau_hash_table_remove(drm_device_t* dev, + struct nouveau_object *obj) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + 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); + } +} + +static struct nouveau_object *nouveau_instance_alloc(drm_device_t* dev) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + struct nouveau_object_store *objs=&dev_priv->objs; + struct nouveau_object *obj; + int instance = -1; + int i = 0, j = 0; + + /* Allocate a block of instance RAM */ + if (!objs->free_instance) { + DRM_ERROR("no free instance ram\n"); + return NULL; + } + for (i=0;i<(objs->num_instance>>5);i++) { + if (objs->inst_bmap[i] == ~0) continue; + for (j=0;j<32;j++) { + if (!(objs->inst_bmap[i] & (1<instance = objs->first_instance; + obj->instance += (instance << (dev_priv->card_type >= NV_40 ? 5 : 4)); + DRM_DEBUG("instance address is 0x%08x\n", instance); + + /* Mark instance slot as used */ + objs->inst_bmap[i] |= (1 << j); + objs->free_instance--; + + return obj; +} + +static void nouveau_object_instance_free(drm_device_t *dev, + struct nouveau_object *obj) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + struct nouveau_object_store *objs=&dev_priv->objs; + int count, i; + uint32_t be, bb; + + if (dev_priv->card_type >= NV_40) + count = 8; + else + count = 4; + + DRM_DEBUG("Instance entry for 0x%08x" + "(engine %d, class 0x%x) before destroy:\n", + obj->handle, obj->engine, obj->class); + for (i=0;iinstance + (i*4))); + + /* Clean RAMIN entry */ + for (i=0;iinstance + (i*4), 0x00000000); + + /* Mark instance as free */ + obj->instance -= objs->first_instance; + obj->instance >>= (dev_priv->card_type >=NV_40 ? 5 : 4); + be = obj->instance / 32; + bb = obj->instance % 32; + objs->inst_bmap[be] &= ~bb; + objs->free_instance++; +} + +/* Where is the hash table located: + + Base address and size can be calculated from this register: + + ht_base = 0x1000 * GetBitField (pNv->PFIFO[0x0210/4],8:4); + ht_size = 0x1000 << GetBitField (pNv->PFIFO[0x0210/4],17:16); + + and the hash table will be located between address PRAMIN + ht_base and + PRAMIN + ht_base + ht_size. Each hash table entry has two longwords. +*/ +void nouveau_hash_table_init(drm_device_t* dev) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + int ht_start, ht_end; + int i; + + dev_priv->objs.ht_bits = 9; + dev_priv->objs.ht_base = 0x10000; + dev_priv->objs.ht_size = (1 << dev_priv->objs.ht_bits); + + NV_WRITE(NV_PFIFO_RAMHT, + (0x03 << 24) /* search 128 */ | + ((dev_priv->objs.ht_bits - 9) << 16) | + ((dev_priv->objs.ht_base >> 16) << 4) + ); + NV_WRITE(NV_PFIFO_RAMFC, 0x00000110); /* RAMIN+0x11000 0.5k */ + NV_WRITE(NV_PFIFO_RAMRO, 0x00000112); /* RAMIN+0x11200 0.5k */ + + dev_priv->objs.first_instance = 0x12000; + dev_priv->objs.free_instance = 1024; /*FIXME*/ + dev_priv->objs.num_instance = 1024; /*FIXME*/ + dev_priv->objs.inst_bmap = drm_calloc + (1, dev_priv->objs.num_instance/32, DRM_MEM_DRIVER); + + /* clear the hash table */ + ht_start = NV_RAMIN+dev_priv->objs.ht_base; + ht_end = ht_start + dev_priv->objs.ht_size; + for (i=ht_start; idev_private; + struct nouveau_object *obj; + uint32_t frame, adjust; + + DRM_DEBUG("offset:0x%08x, size:0x%08x, target:%d, access:%d\n", + offset, size, target, access); + + frame = offset & ~0x00000FFF; + adjust = offset & 0x00000FFF; + + obj = nouveau_instance_alloc(dev); + if (!obj) { + DRM_ERROR("couldn't allocate DMA object\n"); + return obj; + } + + obj->engine = 0; + obj->class = 0; + + NV_WRITE(NV_RAMIN + obj->instance + 0, ((1<<12) + | (1<<13) + | (adjust<<20) + | (access<<14) + | (target<<16) + | 2) + ); + NV_WRITE(NV_RAMIN + obj->instance + 4, + size - 1); + NV_WRITE(NV_RAMIN + obj->instance + 8, + frame | ((access != NV_DMA_ACCESS_RO) ? (1<<1) : 0)); + NV_WRITE(NV_RAMIN + obj->instance + 12, + 0xFFFFFFFF); + + return obj; +} + + +/* Context objects in the instance RAM have the following structure. + * On NV40 they are 32 byte long, on NV30 and smaller 16 bytes. + + NV4 - NV30: + + entry[0] + 11:0 class + 12 chroma key enable + 13 user clip enable + 14 swizzle enable + 17:15 patch config: + scrcopy_and, rop_and, blend_and, scrcopy, srccopy_pre, blend_pre + 18 synchronize enable + 19 endian: 1 big, 0 little + 21:20 dither mode + 23 single step enable + 24 patch status: 0 invalid, 1 valid + 25 context_surface 0: 1 valid + 26 context surface 1: 1 valid + 27 context pattern: 1 valid + 28 context rop: 1 valid + 29,30 context beta, beta4 + entry[1] + 7:0 mono format + 15:8 color format + 31:16 notify instance address + entry[2] + 15:0 dma 0 instance address + 31:16 dma 1 instance address + entry[3] + dma method traps + + NV40: + No idea what the exact format is. Here's what can be deducted: + + entry[0]: + 11:0 class (maybe uses more bits here?) + 17 user clip enable + 21:19 patch config + 25 patch status valid ? + entry[1]: + 15:0 DMA notifier (maybe 20:0) + entry[2]: + 15:0 DMA 0 instance (maybe 20:0) + 24 big endian + entry[3]: + 15:0 DMA 1 instance (maybe 20:0) + entry[4]: + entry[5]: + set to 0? +*/ +static struct nouveau_object *nouveau_context_object_create(drm_device_t* dev, + int class, uint32_t flags0, uint32_t flags1, uint32_t flags2, + struct nouveau_object *dma0, + struct nouveau_object *dma1, + struct nouveau_object *dma_notifier) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + struct nouveau_object *obj; + uint32_t d0, d1, dn; + + DRM_DEBUG("class=%x, dma0=%08x, dma1=%08x, dman=%08x\n", + class, + dma0 ? dma0->handle : 0, + dma1 ? dma1->handle : 0, + dma_notifier ? dma_notifier->handle : 0); + + obj = nouveau_instance_alloc(dev); + if (!obj) { + DRM_ERROR("couldn't allocate context object\n"); + return obj; + } + + obj->engine = 1; + obj->class = class; + + d0 = dma0 ? (dma0->instance >> 4) : 0; + d1 = dma1 ? (dma1->instance >> 4) : 0; + dn = dma_notifier ? (dma_notifier->instance >> 4) : 0; + + if (dev_priv->card_type >= NV_40) { + NV_WRITE(NV_RAMIN + obj->instance + 0, class | flags0); + NV_WRITE(NV_RAMIN + obj->instance + 4, dn | flags1); + NV_WRITE(NV_RAMIN + obj->instance + 8, d0 | flags2); + NV_WRITE(NV_RAMIN + obj->instance + 12, d1); + NV_WRITE(NV_RAMIN + obj->instance + 16, 0x00000000); + NV_WRITE(NV_RAMIN + obj->instance + 20, 0x00000000); + NV_WRITE(NV_RAMIN + obj->instance + 24, 0x00000000); + NV_WRITE(NV_RAMIN + obj->instance + 28, 0x00000000); + } else { + NV_WRITE(NV_RAMIN + obj->instance + 0, class | flags0); + NV_WRITE(NV_RAMIN + obj->instance + 4, (dn << 16) | flags1); + NV_WRITE(NV_RAMIN + obj->instance + 8, d0 | (d1 << 16)); + NV_WRITE(NV_RAMIN + obj->instance + 12, 0); + } + + return obj; +} + +static void +nouveau_object_free(drm_device_t *dev, int fifo_num, struct nouveau_object *obj) +{ + nouveau_object_unlink(dev, fifo_num, obj); + + nouveau_object_instance_free(dev, obj); + nouveau_hash_table_remove(dev, obj); + + drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER); + return; +} + +void nouveau_object_cleanup(drm_device_t *dev, DRMFILE filp) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + int fifo; + + fifo = nouveau_fifo_id_get(dev, filp); + if (fifo == -1) + return; + + while (dev_priv->fifos[fifo].objs) + nouveau_object_free(dev, fifo, dev_priv->fifos[fifo].objs); +} + +int nouveau_ioctl_object_init(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_nouveau_object_init_t init; + struct nouveau_object *obj, *dma0, *dma1, *dman; + int fifo; + + fifo = nouveau_fifo_id_get(dev, filp); + + DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_object_init_t __user *) + data, sizeof(init)); + + //FIXME: check args, only allow trusted objects to be created + + if (nouveau_object_handle_find(dev, fifo, init.handle)) { + DRM_ERROR("Channel %d: handle 0x%08x already exists\n", + fifo, init.handle); + return DRM_ERR(EINVAL); + } + + dma0 = nouveau_object_handle_find(dev, fifo, init.dma0); + if (init.dma0 && !dma0) { + DRM_ERROR("context dma0 - invalid handle 0x%08x\n", init.dma0); + return DRM_ERR(EINVAL); + } + dma1 = nouveau_object_handle_find(dev, fifo, init.dma1); + if (init.dma1 && !dma1) { + DRM_ERROR("context dma1 - invalid handle 0x%08x\n", init.dma0); + return DRM_ERR(EINVAL); + } + dman = nouveau_object_handle_find(dev, fifo, init.dma_notifier); + if (init.dma_notifier && !dman) { + DRM_ERROR("context dman - invalid handle 0x%08x\n", + init.dma_notifier); + return DRM_ERR(EINVAL); + } + + obj = nouveau_context_object_create(dev, init.class, init.flags0, + init.flags1, init.flags2, dma0, dma1, dman); + if (!obj) + return DRM_ERR(ENOMEM); + + obj->handle = init.handle; + + if (nouveau_hash_table_insert(dev, fifo, obj)) { + nouveau_object_free(dev, fifo, obj); + return DRM_ERR(ENOMEM); + } + + nouveau_object_link(dev, fifo, obj); + + return 0; +} + +int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_nouveau_dma_object_init_t init; + struct nouveau_object *obj; + int fifo; + + fifo = nouveau_fifo_id_get(dev, filp); + + DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_dma_object_init_t __user *) + data, sizeof(init)); + + if (nouveau_object_handle_find(dev, fifo, init.handle)) { + DRM_ERROR("Channel %d: handle 0x%08x already exists\n", + fifo, init.handle); + return DRM_ERR(EINVAL); + } + + obj = nouveau_dma_object_create(dev, init.offset, init.size, + init.access, init.target); + if (!obj) + return DRM_ERR(ENOMEM); + + obj->handle = init.handle; + if (nouveau_hash_table_insert(dev, fifo, obj)) { + nouveau_object_free(dev, fifo, obj); + return DRM_ERR(ENOMEM); + } + + nouveau_object_link(dev, fifo, obj); + + return 0; +} + -- cgit v1.2.3 From 97291a6ad05848b05af69e52453d93db1e96473b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 2 Sep 2006 22:25:26 +1000 Subject: Use DMA_IN_MEMORY for DMA objects. This is needed for a DDX change that will be committed soon after this. Without the change, MEMFORMAT_DMA_OUT appears to have no effect. --- shared-core/nouveau_object.c | 7 +++++-- 1 file changed, 5 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 fb30d529..f5c16c5e 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -338,14 +338,17 @@ struct nouveau_object *nouveau_dma_object_create(drm_device_t* dev, | (adjust<<20) | (access<<14) | (target<<16) - | 2) + | 0x3D /* DMA_IN_MEMORY */) ); NV_WRITE(NV_RAMIN + obj->instance + 4, size - 1); NV_WRITE(NV_RAMIN + obj->instance + 8, frame | ((access != NV_DMA_ACCESS_RO) ? (1<<1) : 0)); + /* I don't actually know what this is, the DMA objects I see + * in renouveau dumps usually have this as the same as +8 + */ NV_WRITE(NV_RAMIN + obj->instance + 12, - 0xFFFFFFFF); + frame | ((access != NV_DMA_ACCESS_RO) ? (1<<1) : 0)); return obj; } -- cgit v1.2.3 From 0ef29768ca909421539c3d8f65bb8e94912fa597 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 7 Sep 2006 23:59:19 +1000 Subject: Fix second start of X server without module reload beforehand, and a couple of other fixes. - Mark the correct RAMIN slots as free (oops) - Remove a VRAM alloc that shouldn't have been there (oops) - Move HT init out of firstopen() and into dma_init() - Setup PFIFO_RAM{HT,FC,RO} in pfifo_init() --- shared-core/nouveau_object.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index f5c16c5e..a7fe06c2 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -241,7 +241,7 @@ static void nouveau_object_instance_free(drm_device_t *dev, obj->instance >>= (dev_priv->card_type >=NV_40 ? 5 : 4); be = obj->instance / 32; bb = obj->instance % 32; - objs->inst_bmap[be] &= ~bb; + objs->inst_bmap[be] &= ~(1<free_instance++; } @@ -265,14 +265,6 @@ void nouveau_hash_table_init(drm_device_t* dev) dev_priv->objs.ht_base = 0x10000; dev_priv->objs.ht_size = (1 << dev_priv->objs.ht_bits); - NV_WRITE(NV_PFIFO_RAMHT, - (0x03 << 24) /* search 128 */ | - ((dev_priv->objs.ht_bits - 9) << 16) | - ((dev_priv->objs.ht_base >> 16) << 4) - ); - NV_WRITE(NV_PFIFO_RAMFC, 0x00000110); /* RAMIN+0x11000 0.5k */ - NV_WRITE(NV_PFIFO_RAMRO, 0x00000112); /* RAMIN+0x11200 0.5k */ - dev_priv->objs.first_instance = 0x12000; dev_priv->objs.free_instance = 1024; /*FIXME*/ dev_priv->objs.num_instance = 1024; /*FIXME*/ -- cgit v1.2.3 From aa80e2f48f291aa41524dfb53023499c91473705 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Sep 2006 07:35:55 +1000 Subject: Add copyright notices while I still remember.. --- shared-core/nouveau_object.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index a7fe06c2..4e0571b4 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -1,3 +1,35 @@ +/* + * Copyright (C) 2006 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. + * + */ + +/* + * Authors: + * Ben Skeggs + */ + #include "drmP.h" #include "drm.h" #include "nouveau_drv.h" -- cgit v1.2.3 From 98e718d48fcd166accf1af3c017c34e331ab09cb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 17 Oct 2006 07:29:31 +1100 Subject: NV40: FIFO context switching now WorksForMe(tm) --- 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 4e0571b4..5f11cfa7 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -297,7 +297,7 @@ void nouveau_hash_table_init(drm_device_t* dev) dev_priv->objs.ht_base = 0x10000; dev_priv->objs.ht_size = (1 << dev_priv->objs.ht_bits); - dev_priv->objs.first_instance = 0x12000; + dev_priv->objs.first_instance = 0x13000; dev_priv->objs.free_instance = 1024; /*FIXME*/ dev_priv->objs.num_instance = 1024; /*FIXME*/ dev_priv->objs.inst_bmap = drm_calloc -- cgit v1.2.3 From 4b43ee63f90c93701c9f1cdf7fefd1816b316d33 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 17 Oct 2006 12:33:49 +1100 Subject: NV40: *Now* fifo ctx switching works for me.. Ok, I lied before.. it was a fluke it worked and required magic to repeat it.. It actually helps to fill in RAMFC entries in the correct place. The code also clears RAMIN entirely instead of just the hash-table. --- shared-core/nouveau_object.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 5f11cfa7..18c50763 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -303,10 +303,8 @@ void nouveau_hash_table_init(drm_device_t* dev) dev_priv->objs.inst_bmap = drm_calloc (1, dev_priv->objs.num_instance/32, DRM_MEM_DRIVER); - /* clear the hash table */ - ht_start = NV_RAMIN+dev_priv->objs.ht_base; - ht_end = ht_start + dev_priv->objs.ht_size; - for (i=ht_start; i Date: Tue, 17 Oct 2006 23:44:05 +1100 Subject: Useful output on a FIFO error interrupt. --- shared-core/nouveau_object.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 18c50763..78a4b78f 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -290,7 +290,6 @@ static void nouveau_object_instance_free(drm_device_t *dev, void nouveau_hash_table_init(drm_device_t* dev) { drm_nouveau_private_t *dev_priv=dev->dev_private; - int ht_start, ht_end; int i; dev_priv->objs.ht_bits = 9; -- cgit v1.2.3 From 3ea0500be1ab7a058c90be35b5d8d2be26692f6a Mon Sep 17 00:00:00 2001 From: Stephane Marchesin Date: Sat, 4 Nov 2006 16:56:10 +0100 Subject: Move the context object creation flag handling to the drm. --- shared-core/nouveau_object.c | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 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 78a4b78f..b539ee65 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -427,7 +427,7 @@ struct nouveau_object *nouveau_dma_object_create(drm_device_t* dev, set to 0? */ static struct nouveau_object *nouveau_context_object_create(drm_device_t* dev, - int class, uint32_t flags0, uint32_t flags1, uint32_t flags2, + int class, uint32_t flags, struct nouveau_object *dma0, struct nouveau_object *dma1, struct nouveau_object *dma_notifier) @@ -435,6 +435,40 @@ static struct nouveau_object *nouveau_context_object_create(drm_device_t* dev, drm_nouveau_private_t *dev_priv=dev->dev_private; struct nouveau_object *obj; uint32_t d0, d1, dn; + uint32_t flags0,flags1,flags2; + flags0=0;flags1=0;flags2=0; + + if (dev_priv->card_type >= NV_40) { + if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND) + flags0 |= 0x02080000; + else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY) + flags0 |= 0x02080000; + if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE) + flags0 |= 0x00020000; +#ifdef __BIG_ENDIAN + if (flags & NV_DMA_CONTEXT_FLAGS_MONO) + flags1 |= 0x01000000; + flags2 |= 0x01000000; +#else + if (flags & NV_DMA_CONTEXT_FLAGS_MONO) + flags1 |= 0x02000000; +#endif + } else { + if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND) + flags0 |= 0x01008000; + else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY) + flags0 |= 0x01018000; + if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE) + flags0 |= 0x00002000; +#ifdef __BIG_ENDIAN + flags0 |= 0x00080000; + if (flags & NV_DMA_CONTEXT_FLAGS_MONO) + flags1 |= 0x00000001; +#else + if (flags & NV_DMA_CONTEXT_FLAGS_MONO) + flags1 |= 0x00000002; +#endif + } DRM_DEBUG("class=%x, dma0=%08x, dma1=%08x, dman=%08x\n", class, @@ -536,8 +570,8 @@ int nouveau_ioctl_object_init(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - obj = nouveau_context_object_create(dev, init.class, init.flags0, - init.flags1, init.flags2, dma0, dma1, dman); + obj = nouveau_context_object_create(dev, init.class, init.flags, + dma0, dma1, dman); if (!obj) return DRM_ERR(ENOMEM); -- cgit v1.2.3 From 0c34d0f31a691bb649ed69f19e93fc1a723aa1d4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 6 Nov 2006 05:46:03 +1100 Subject: Leave the bottom 64kb of RAMIN untouched. The binary driver will screw up either it's init or shutdown, leaving the screen(s) in an unusable state without this. Something important in there? --- shared-core/nouveau_object.c | 8 ++++++-- 1 file changed, 6 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 b539ee65..935297fa 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -302,8 +302,12 @@ void nouveau_hash_table_init(drm_device_t* dev) dev_priv->objs.inst_bmap = drm_calloc (1, dev_priv->objs.num_instance/32, DRM_MEM_DRIVER); - /* clear all of RAMIN */ - for (i=0x00700000; i<0x00800000; i+=4) + /* clear all of RAMIN + * NOTE: except the bottom 0x10000 bytes, the binary driver doesn't + * like this and will die either sometime during init, or during + * shutdown - leaving the screen in an unusable state... + */ + for (i=0x00710000; i<0x00800000; i+=4) NV_WRITE(i, 0x00000000); } -- cgit v1.2.3 From 7002082944a69e1d11b0146b1176fd4293581dcd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 14 Nov 2006 08:11:49 +1100 Subject: Restructure initialisation a bit. - Do important card init in firstopen - Give each channel it's own cmdbuf dma object - Move RAMHT config state to the same place as RAMRO/RAMFC - Make sure instance mem for objects is *after* RAM{FC,HT,RO} --- shared-core/nouveau_object.c | 42 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 935297fa..abd8bec5 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -132,15 +132,14 @@ static uint32_t nouveau_handle_hash(drm_device_t* dev, uint32_t handle, int fifo) { drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_object_store *objs=&dev_priv->objs; uint32_t hash = 0; int i; - for (i=32;i>0;i-=objs->ht_bits) { - hash ^= (handle & ((1 << objs->ht_bits) - 1)); - handle >>= objs->ht_bits; + for (i=32;i>0;i-=dev_priv->ramht_bits) { + hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1)); + handle >>= dev_priv->ramht_bits; } - hash ^= fifo << (objs->ht_bits - 4); + hash ^= fifo << (dev_priv->ramht_bits - 4); return hash << 3; } @@ -148,9 +147,8 @@ static int nouveau_hash_table_insert(drm_device_t* dev, int fifo, struct nouveau_object *obj) { drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_object_store *objs=&dev_priv->objs; - int ht_base = NV_RAMIN + objs->ht_base; - int ht_end = ht_base + objs->ht_size; + int ht_base = NV_RAMIN + dev_priv->ramht_offset; + int ht_end = ht_base + dev_priv->ramht_size; int o_ofs, ofs; o_ofs = ofs = nouveau_handle_hash(dev, obj->handle, fifo); @@ -277,38 +275,18 @@ static void nouveau_object_instance_free(drm_device_t *dev, objs->free_instance++; } -/* Where is the hash table located: - - Base address and size can be calculated from this register: - - ht_base = 0x1000 * GetBitField (pNv->PFIFO[0x0210/4],8:4); - ht_size = 0x1000 << GetBitField (pNv->PFIFO[0x0210/4],17:16); - - and the hash table will be located between address PRAMIN + ht_base and - PRAMIN + ht_base + ht_size. Each hash table entry has two longwords. -*/ -void nouveau_hash_table_init(drm_device_t* dev) +int nouveau_object_init(drm_device_t* dev) { drm_nouveau_private_t *dev_priv=dev->dev_private; - int i; - - dev_priv->objs.ht_bits = 9; - dev_priv->objs.ht_base = 0x10000; - dev_priv->objs.ht_size = (1 << dev_priv->objs.ht_bits); - dev_priv->objs.first_instance = 0x13000; + dev_priv->objs.first_instance = + dev_priv->ramfc_offset +dev_priv->ramfc_size; dev_priv->objs.free_instance = 1024; /*FIXME*/ dev_priv->objs.num_instance = 1024; /*FIXME*/ dev_priv->objs.inst_bmap = drm_calloc (1, dev_priv->objs.num_instance/32, DRM_MEM_DRIVER); - /* clear all of RAMIN - * NOTE: except the bottom 0x10000 bytes, the binary driver doesn't - * like this and will die either sometime during init, or during - * shutdown - leaving the screen in an unusable state... - */ - for (i=0x00710000; i<0x00800000; i+=4) - NV_WRITE(i, 0x00000000); + return 0; } /* -- cgit v1.2.3 From e9194dd1b068666dd94e73d95dc3cd031a89a6b7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 18 Nov 2006 10:03:45 +1100 Subject: Check some return vals, fixes a couple of oopses. --- shared-core/nouveau_object.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index abd8bec5..0db92ec4 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -523,6 +523,8 @@ int nouveau_ioctl_object_init(DRM_IOCTL_ARGS) int fifo; fifo = nouveau_fifo_id_get(dev, filp); + if (fifo == -1) + return DRM_ERR(EINVAL); DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_object_init_t __user *) data, sizeof(init)); @@ -577,6 +579,8 @@ int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS) int fifo; fifo = nouveau_fifo_id_get(dev, filp); + if (fifo == -1) + return DRM_ERR(EINVAL); DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_dma_object_init_t __user *) data, sizeof(init)); -- cgit v1.2.3 From b1a9a769711d83af8ab4c7ba4eec52a05a351533 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 30 Nov 2006 08:35:42 +1100 Subject: Wrap access to objects in RAMIN. This will make it easier to support extra RAMIN in vram at a later point. --- shared-core/nouveau_object.c | 74 ++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 34 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 0db92ec4..2c899335 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -40,6 +40,15 @@ * - 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, uint32_t instance) +{ + return (instance>>4); +} + static void nouveau_object_link(drm_device_t *dev, int fifo_num, struct nouveau_object *obj) { @@ -171,14 +180,14 @@ static int nouveau_hash_table_insert(drm_device_t* dev, int fifo, NV_WRITE(NV_RAMHT_CONTEXT_OFFSET + ofs, (fifo << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT) | - (obj->instance>>4) + nouveau_chip_instance_get(dev, obj->instance) ); else NV_WRITE(NV_RAMHT_CONTEXT_OFFSET + ofs, NV_RAMHT_CONTEXT_VALID | (fifo << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | (obj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT) | - (obj->instance>>4) + nouveau_chip_instance_get(dev, obj->instance) ); obj->ht_loc = ofs; @@ -255,16 +264,15 @@ static void nouveau_object_instance_free(drm_device_t *dev, else count = 4; + /* 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;iinstance + (i*4))); - - /* Clean RAMIN entry */ - for (i=0;iinstance + (i*4), 0x00000000); + INSTANCE_RD(obj->instance, i)); + INSTANCE_WR(obj->instance, i, 0x00000000); + } /* Mark instance as free */ obj->instance -= objs->first_instance; @@ -336,21 +344,18 @@ struct nouveau_object *nouveau_dma_object_create(drm_device_t* dev, obj->engine = 0; obj->class = 0; - NV_WRITE(NV_RAMIN + obj->instance + 0, ((1<<12) - | (1<<13) - | (adjust<<20) - | (access<<14) - | (target<<16) - | 0x3D /* DMA_IN_MEMORY */) - ); - NV_WRITE(NV_RAMIN + obj->instance + 4, - size - 1); - NV_WRITE(NV_RAMIN + obj->instance + 8, + INSTANCE_WR(obj->instance, 0, ((1<<12) | (1<<13) | + (adjust << 20) | + (access << 14) | + (target << 16) | + 0x3D /* DMA_IN_MEMORY */)); + INSTANCE_WR(obj->instance, 1, size-1); + INSTANCE_WR(obj->instance, 2, frame | ((access != NV_DMA_ACCESS_RO) ? (1<<1) : 0)); /* I don't actually know what this is, the DMA objects I see * in renouveau dumps usually have this as the same as +8 */ - NV_WRITE(NV_RAMIN + obj->instance + 12, + INSTANCE_WR(obj->instance, 3, frame | ((access != NV_DMA_ACCESS_RO) ? (1<<1) : 0)); return obj; @@ -467,24 +472,25 @@ static struct nouveau_object *nouveau_context_object_create(drm_device_t* dev, obj->engine = 1; obj->class = class; - d0 = dma0 ? (dma0->instance >> 4) : 0; - d1 = dma1 ? (dma1->instance >> 4) : 0; - dn = dma_notifier ? (dma_notifier->instance >> 4) : 0; + d0 = dma0 ? nouveau_chip_instance_get(dev, dma0->instance) : 0; + d1 = dma1 ? nouveau_chip_instance_get(dev, dma1->instance) : 0; + dn = dma_notifier ? + nouveau_chip_instance_get(dev, dma_notifier->instance) : 0; if (dev_priv->card_type >= NV_40) { - NV_WRITE(NV_RAMIN + obj->instance + 0, class | flags0); - NV_WRITE(NV_RAMIN + obj->instance + 4, dn | flags1); - NV_WRITE(NV_RAMIN + obj->instance + 8, d0 | flags2); - NV_WRITE(NV_RAMIN + obj->instance + 12, d1); - NV_WRITE(NV_RAMIN + obj->instance + 16, 0x00000000); - NV_WRITE(NV_RAMIN + obj->instance + 20, 0x00000000); - NV_WRITE(NV_RAMIN + obj->instance + 24, 0x00000000); - NV_WRITE(NV_RAMIN + obj->instance + 28, 0x00000000); + INSTANCE_WR(obj->instance, 0, class | flags0); + INSTANCE_WR(obj->instance, 1, dn | flags1); + INSTANCE_WR(obj->instance, 2, d0 | flags2); + INSTANCE_WR(obj->instance, 3, d1); + 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 { - NV_WRITE(NV_RAMIN + obj->instance + 0, class | flags0); - NV_WRITE(NV_RAMIN + obj->instance + 4, (dn << 16) | flags1); - NV_WRITE(NV_RAMIN + obj->instance + 8, d0 | (d1 << 16)); - NV_WRITE(NV_RAMIN + obj->instance + 12, 0); + INSTANCE_WR(obj->instance, 0, class | flags0); + INSTANCE_WR(obj->instance, 1, (dn << 16) | flags1); + INSTANCE_WR(obj->instance, 2, d0 | (d1 << 16)); + INSTANCE_WR(obj->instance, 3, 0); } return obj; -- cgit v1.2.3 From 80d75cf6950acf1a00a031ceb6511b26dcc9b056 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 30 Nov 2006 10:31:42 +1100 Subject: Use nouveau_mem.c to allocate RAMIN. --- shared-core/nouveau_object.c | 67 ++++++++++---------------------------------- 1 file changed, 15 insertions(+), 52 deletions(-) (limited to 'shared-core/nouveau_object.c') diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 2c899335..c11b05eb 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -44,9 +44,13 @@ * 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, uint32_t instance) +uint32_t nouveau_chip_instance_get(drm_device_t *dev, + struct mem_block *mem) { - return (instance>>4); + 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, int fifo_num, @@ -212,27 +216,7 @@ static void nouveau_hash_table_remove(drm_device_t* dev, static struct nouveau_object *nouveau_instance_alloc(drm_device_t* dev) { drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_object_store *objs=&dev_priv->objs; struct nouveau_object *obj; - int instance = -1; - int i = 0, j = 0; - - /* Allocate a block of instance RAM */ - if (!objs->free_instance) { - DRM_ERROR("no free instance ram\n"); - return NULL; - } - for (i=0;i<(objs->num_instance>>5);i++) { - if (objs->inst_bmap[i] == ~0) continue; - for (j=0;j<32;j++) { - if (!(objs->inst_bmap[i] & (1<instance = objs->first_instance; - obj->instance += (instance << (dev_priv->card_type >= NV_40 ? 5 : 4)); - DRM_DEBUG("instance address is 0x%08x\n", instance); - - /* Mark instance slot as used */ - objs->inst_bmap[i] |= (1 << j); - objs->free_instance--; + 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; + } return obj; } @@ -255,9 +239,7 @@ static void nouveau_object_instance_free(drm_device_t *dev, struct nouveau_object *obj) { drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_object_store *objs=&dev_priv->objs; int count, i; - uint32_t be, bb; if (dev_priv->card_type >= NV_40) count = 8; @@ -274,27 +256,8 @@ static void nouveau_object_instance_free(drm_device_t *dev, INSTANCE_WR(obj->instance, i, 0x00000000); } - /* Mark instance as free */ - obj->instance -= objs->first_instance; - obj->instance >>= (dev_priv->card_type >=NV_40 ? 5 : 4); - be = obj->instance / 32; - bb = obj->instance % 32; - objs->inst_bmap[be] &= ~(1<free_instance++; -} - -int nouveau_object_init(drm_device_t* dev) -{ - drm_nouveau_private_t *dev_priv=dev->dev_private; - - dev_priv->objs.first_instance = - dev_priv->ramfc_offset +dev_priv->ramfc_size; - dev_priv->objs.free_instance = 1024; /*FIXME*/ - dev_priv->objs.num_instance = 1024; /*FIXME*/ - dev_priv->objs.inst_bmap = drm_calloc - (1, dev_priv->objs.num_instance/32, DRM_MEM_DRIVER); - - return 0; + /* Free RAMIN */ + nouveau_instmem_free(dev, obj->instance); } /* -- cgit v1.2.3