diff options
Diffstat (limited to 'linux')
-rw-r--r-- | linux/Makefile.linux | 3 | ||||
-rw-r--r-- | linux/context.c | 1 | ||||
-rw-r--r-- | linux/ctxbitmap.c | 7 | ||||
-rw-r--r-- | linux/dma.c | 1 | ||||
-rw-r--r-- | linux/lists.c | 1 | ||||
-rw-r--r-- | linux/lock.c | 3 | ||||
-rw-r--r-- | linux/mga_clear.c | 17 | ||||
-rw-r--r-- | linux/mga_context.c | 245 | ||||
-rw-r--r-- | linux/mga_dma.c | 239 | ||||
-rw-r--r-- | linux/mga_dma.h | 2 | ||||
-rw-r--r-- | linux/mga_drv.c | 16 | ||||
-rw-r--r-- | linux/mga_drv.h | 19 |
12 files changed, 478 insertions, 76 deletions
diff --git a/linux/Makefile.linux b/linux/Makefile.linux index c0ab34ab..5cc5334f 100644 --- a/linux/Makefile.linux +++ b/linux/Makefile.linux @@ -71,7 +71,8 @@ GAMMAHEADERS= gamma_drv.h $(DRMHEADERS) TDFXOBJS= tdfx_drv.o tdfx_context.o TDFXHEADERS= tdfx_drv.h $(DRMHEADERS) -MGAOBJS= mga_drv.o mga_dma.o mga_bufs.o mga_state.o mga_clear.o +MGAOBJS= mga_drv.o mga_dma.o mga_bufs.o mga_state.o mga_clear.o \ + mga_context.o MGAHEADERS= mga_drv.h mga_drm_public.h $(DRMHEADERS) R128OBJS= r128_drv.o r128_context.o diff --git a/linux/context.c b/linux/context.c index 998401d1..9edfeae9 100644 --- a/linux/context.c +++ b/linux/context.c @@ -281,6 +281,7 @@ int drm_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, finalization) */ while (test_and_set_bit(0, &dev->interrupt_flag)) { + printk("Calling schedule from rmctx\n"); schedule(); if (signal_pending(current)) { clear_bit(0, &dev->interrupt_flag); diff --git a/linux/ctxbitmap.c b/linux/ctxbitmap.c index ad23331c..262a4f22 100644 --- a/linux/ctxbitmap.c +++ b/linux/ctxbitmap.c @@ -41,7 +41,7 @@ void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle) return; } failed: - DRM_DEBUG("Attempt to free invalid context handle: %d\n", + DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle); return; } @@ -53,6 +53,7 @@ int drm_ctxbitmap_next(drm_device_t *dev) bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP); if (bit < DRM_MAX_CTXBITMAP) { set_bit(bit, dev->ctx_bitmap); + printk("drm_ctxbitmap_next bit : %d\n", bit); return bit; } return -1; @@ -61,6 +62,7 @@ int drm_ctxbitmap_next(drm_device_t *dev) int drm_ctxbitmap_init(drm_device_t *dev) { int i; + int temp; dev->ctx_bitmap = (unsigned long *) drm_alloc(PAGE_SIZE * 4, DRM_MEM_CTXBITMAP); @@ -69,7 +71,8 @@ int drm_ctxbitmap_init(drm_device_t *dev) } memset((void *) dev->ctx_bitmap, 0, PAGE_SIZE * 4); for(i = 0; i < DRM_RESERVED_CONTEXTS; i++) { - drm_ctxbitmap_next(dev); + temp = drm_ctxbitmap_next(dev); + printk("drm_ctxbitmap_init : %d\n", temp); } return 0; diff --git a/linux/dma.c b/linux/dma.c index d796e679..099311c2 100644 --- a/linux/dma.c +++ b/linux/dma.c @@ -402,6 +402,7 @@ int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d) atomic_inc(&q->block_count); for (;;) { if (!atomic_read(&q->block_write)) break; + printk("Calling schedule from dma_enqueue\n"); schedule(); if (signal_pending(current)) { atomic_dec(&q->use_count); diff --git a/linux/lists.c b/linux/lists.c index 6917527b..17c9759a 100644 --- a/linux/lists.c +++ b/linux/lists.c @@ -230,6 +230,7 @@ drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block) for (;;) { if (!atomic_read(&bl->wfh) && (buf = drm_freelist_try(bl))) break; + printk("calling schedule from freelist_get\n"); schedule(); if (signal_pending(current)) break; } diff --git a/linux/lock.c b/linux/lock.c index b1c38e28..3f7eaff6 100644 --- a/linux/lock.c +++ b/linux/lock.c @@ -133,12 +133,15 @@ int drm_flush_queue(drm_device_t *dev, int context) atomic_inc(&q->block_count); for (;;) { if (!DRM_BUFCOUNT(&q->waitlist)) break; + printk("Calling schedule from flush_queue : %d\n", + DRM_BUFCOUNT(&q->waitlist)); schedule(); if (signal_pending(current)) { ret = -EINTR; /* Can't restart */ break; } } + printk("Exited out of schedule from flush_queue\n"); atomic_dec(&q->block_count); current->state = TASK_RUNNING; remove_wait_queue(&q->flush_queue, &entry); diff --git a/linux/mga_clear.c b/linux/mga_clear.c index e9eef908..cb2e9d02 100644 --- a/linux/mga_clear.c +++ b/linux/mga_clear.c @@ -139,7 +139,9 @@ static int mgaClearBuffers(drm_device_t *dev, d.request_sizes = NULL; d.granted_count = 0; - drm_dma_enqueue(dev, &d); + atomic_inc(&dev_priv->pending_bufs); + if((drm_dma_enqueue(dev, &d)) != 0) + atomic_dec(&dev_priv->pending_bufs); mga_dma_schedule(dev, 1); return 0; } @@ -208,8 +210,10 @@ int mgaSwapBuffers(drm_device_t *dev, int flags) d.request_indices = NULL; d.request_sizes = NULL; d.granted_count = 0; - - drm_dma_enqueue(dev, &d); + + atomic_inc(&dev_priv->pending_bufs); + if((drm_dma_enqueue(dev, &d)) != 0) + atomic_dec(&dev_priv->pending_bufs); mga_dma_schedule(dev, 1); return 0; } @@ -265,7 +269,9 @@ static int mgaIload(drm_device_t *dev, drm_mga_iload_t *args) d.request_sizes = NULL; d.granted_count = 0; - drm_dma_enqueue(dev, &d); + atomic_inc(&dev_priv->pending_bufs); + if((drm_dma_enqueue(dev, &d)) != 0) + atomic_dec(&dev_priv->pending_bufs); mga_dma_schedule(dev, 1); return 0; @@ -390,7 +396,10 @@ int mga_dma(struct inode *inode, struct file *filp, unsigned int cmd, */ mgaCopyAndVerifyState( dev_priv, buf_priv ); + atomic_inc(&dev_priv->pending_bufs); retcode = drm_dma_enqueue(dev, &d); + if(retcode != 0) + atomic_dec(&dev_priv->pending_bufs); mga_dma_schedule(dev, 1); } diff --git a/linux/mga_context.c b/linux/mga_context.c new file mode 100644 index 00000000..4e793213 --- /dev/null +++ b/linux/mga_context.c @@ -0,0 +1,245 @@ +/* mga_context.c -- IOCTLs for mga contexts -*- linux-c -*- + * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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 + * PRECISION INSIGHT 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. + * + * Author: Rickard E. (Rik) Faith <faith@precisioninsight.com> + * + * $XFree86$ + * + */ + +#include <linux/sched.h> + +#define __NO_VERSION__ +#include "drmP.h" +#include "mga_drv.h" + +static int mga_alloc_queue(drm_device_t *dev) +{ + int temp = drm_ctxbitmap_next(dev); + printk("mga_alloc_queue: %d\n", temp); + return temp; +} + +int mga_context_switch(drm_device_t *dev, int old, int new) +{ + char buf[64]; + + atomic_inc(&dev->total_ctx); + + if (test_and_set_bit(0, &dev->context_flag)) { + DRM_ERROR("Reentering -- FIXME\n"); + return -EBUSY; + } + +#if DRM_DMA_HISTOGRAM + dev->ctx_start = get_cycles(); +#endif + + printk("Context switch from %d to %d\n", old, new); + + if (new == dev->last_context) { + clear_bit(0, &dev->context_flag); + return 0; + } + + if (drm_flags & DRM_FLAG_NOCTX) { + mga_context_switch_complete(dev, new); + } else { + sprintf(buf, "C %d %d\n", old, new); + drm_write_string(dev, buf); + } + + return 0; +} + +int mga_context_switch_complete(drm_device_t *dev, int new) +{ + dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ + dev->last_switch = jiffies; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("Lock isn't held after context switch\n"); + } + + /* If a context switch is ever initiated + when the kernel holds the lock, release + that lock here. */ +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles() + - dev->ctx_start)]); + +#endif + clear_bit(0, &dev->context_flag); + wake_up(&dev->context_wait); + + return 0; +} + +int mga_resctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_res_t res; + drm_ctx_t ctx; + int i; + + printk("%d\n", DRM_RESERVED_CONTEXTS); + copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (res.count >= DRM_RESERVED_CONTEXTS) { + memset(&ctx, 0, sizeof(ctx)); + for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { + ctx.handle = i; + copy_to_user_ret(&res.contexts[i], + &i, + sizeof(i), + -EFAULT); + } + } + res.count = DRM_RESERVED_CONTEXTS; + copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + return 0; +} + +int mga_addctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if ((ctx.handle = mga_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { + /* Skip kernel's context and get a new one. */ + ctx.handle = mga_alloc_queue(dev); + } + if (ctx.handle == -1) { + printk("Not enough free contexts.\n"); + /* Should this return -EBUSY instead? */ + return -ENOMEM; + } + printk("%d\n", ctx.handle); + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int mga_modctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + /* This does nothing for the mga */ + return 0; +} + +int mga_getctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + /* This is 0, because we don't hanlde any context flags */ + ctx.flags = 0; + copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int mga_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + printk("%d\n", ctx.handle); + return mga_context_switch(dev, dev->last_context, ctx.handle); +} + +int mga_newctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + printk("%d\n", ctx.handle); + mga_context_switch_complete(dev, ctx.handle); + + return 0; +} + +int mga_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + drm_queue_t *q; + drm_buf_t *buf; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + printk("%d\n", ctx.handle); + if(ctx.handle == DRM_KERNEL_CONTEXT) { + q = dev->queuelist[ctx.handle]; + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + /* No longer in use */ + atomic_dec(&q->use_count); + return -EINVAL; + } + atomic_inc(&q->finalization); /* Mark queue in finalization state */ + atomic_sub(2, &q->use_count); + /* Mark queue as unused (pending finalization) */ + + while (test_and_set_bit(0, &dev->interrupt_flag)) { + printk("Calling schedule from rmctx\n"); + schedule(); + if (signal_pending(current)) { + clear_bit(0, &dev->interrupt_flag); + return -EINTR; + } + } + + /* Remove queued buffers */ + while ((buf = drm_waitlist_get(&q->waitlist))) { + drm_free_buffer(dev, buf); + } + clear_bit(0, &dev->interrupt_flag); + + /* Wakeup blocked processes */ + wake_up_interruptible(&q->read_queue); + wake_up_interruptible(&q->write_queue); + wake_up_interruptible(&q->flush_queue); + + /* Finalization over. Queue is made + available when both use_count and + finalization become 0, which won't + happen until all the waiting processes + stop waiting. */ + atomic_dec(&q->finalization); + } else { + drm_ctxbitmap_free(dev, ctx.handle); + } + + return 0; +} diff --git a/linux/mga_dma.c b/linux/mga_dma.c index 1464576f..f4732fe6 100644 --- a/linux/mga_dma.c +++ b/linux/mga_dma.c @@ -82,12 +82,67 @@ int mga_dma_cleanup(drm_device_t *dev) dev->dev_private = NULL; } - /* NOT DONE: Free the dma buffer dev privates. These will - * disappear with Jeff's work, anyway. - */ return 0; } +static int mga_alloc_kernel_queue(drm_device_t *dev) +{ + drm_queue_t *queue = NULL; + /* Allocate a new queue */ + down(&dev->struct_sem); + + if(dev->queue_count != 0) { + /* Reseting the kernel context here is not + * a race, since it can only happen when that + * queue is empty. + */ + queue = dev->queuelist[DRM_KERNEL_CONTEXT]; + printk("Kernel queue already allocated\n"); + } else { + queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES); + if(!queue) { + up(&dev->struct_sem); + printk("out of memory\n"); + return -ENOMEM; + } + ++dev->queue_count; + dev->queuelist = drm_alloc(sizeof(*dev->queuelist), + DRM_MEM_QUEUES); + if(!dev->queuelist) { + up(&dev->struct_sem); + drm_free(queue, sizeof(*queue), DRM_MEM_QUEUES); + printk("out of memory\n"); + return -ENOMEM; + } + } + + memset(queue, 0, sizeof(*queue)); + atomic_set(&queue->use_count, 1); + atomic_set(&queue->finalization, 0); + atomic_set(&queue->block_count, 0); + atomic_set(&queue->block_read, 0); + atomic_set(&queue->block_write, 0); + atomic_set(&queue->total_queued, 0); + atomic_set(&queue->total_flushed, 0); + atomic_set(&queue->total_locks, 0); + + init_waitqueue_head(&queue->write_queue); + init_waitqueue_head(&queue->read_queue); + init_waitqueue_head(&queue->flush_queue); + + queue->flags = 0; + + drm_waitlist_create(&queue->waitlist, dev->dma->buf_count); + + dev->queue_slots = 1; + dev->queuelist[DRM_KERNEL_CONTEXT] = queue; + dev->queue_count--; + + up(&dev->struct_sem); + printk("%d (new)\n", dev->queue_count - 1); + return DRM_KERNEL_CONTEXT; +} + static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { drm_mga_private_t *dev_priv; drm_map_t *prim_map = NULL; @@ -99,15 +154,22 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { if(dev_priv == NULL) return -ENOMEM; dev->dev_private = (void *) dev_priv; - DRM_DEBUG("dev_private\n"); + printk("dev_private\n"); memset(dev_priv, 0, sizeof(drm_mga_private_t)); + atomic_set(&dev_priv->pending_bufs, 0); + if((init->reserved_map_idx >= dev->map_count) || (init->buffer_map_idx >= dev->map_count)) { mga_dma_cleanup(dev); - DRM_DEBUG("reserved_map or buffer_map are invalid\n"); + printk("reserved_map or buffer_map are invalid\n"); return -EINVAL; } + + if(mga_alloc_kernel_queue(dev) != DRM_KERNEL_CONTEXT) { + mga_dma_cleanup(dev); + DRM_ERROR("Kernel context queue not present\n"); + } dev_priv->reserved_map_idx = init->reserved_map_idx; dev_priv->buffer_map_idx = init->buffer_map_idx; @@ -115,7 +177,7 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { dev_priv->sarea_priv = (drm_mga_sarea_t *) ((u8 *)sarea_map->handle + init->sarea_priv_offset); - DRM_DEBUG("sarea_priv\n"); + printk("sarea_priv\n"); /* Scale primary size to the next page */ dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / @@ -137,24 +199,24 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { dev_priv->mAccess = init->mAccess; - DRM_DEBUG("memcpy\n"); + printk("memcpy\n"); memcpy(&dev_priv->WarpIndex, &init->WarpIndex, sizeof(mgaWarpIndex) * MGA_MAX_WARP_PIPES); - DRM_DEBUG("memcpy done\n"); + printk("memcpy done\n"); prim_map = dev->maplist[init->reserved_map_idx]; dev_priv->prim_phys_head = dev->agp->base + init->reserved_map_agpstart; temp = init->warp_ucode_size + dev_priv->primary_size; temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; - DRM_DEBUG("temp : %x\n", temp); - DRM_DEBUG("dev->agp->base: %lx\n", dev->agp->base); - DRM_DEBUG("init->reserved_map_agpstart: %x\n", init->reserved_map_agpstart); + printk("temp : %x\n", temp); + printk("dev->agp->base: %lx\n", dev->agp->base); + printk("init->reserved_map_agpstart: %x\n", init->reserved_map_agpstart); dev_priv->ioremap = drm_ioremap(dev->agp->base + init->reserved_map_agpstart, temp); if(dev_priv->ioremap == NULL) { - DRM_DEBUG("Ioremap failed\n"); + printk("Ioremap failed\n"); mga_dma_cleanup(dev); return -ENOMEM; } @@ -162,12 +224,12 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { dev_priv->prim_head = (u32 *)dev_priv->ioremap; - DRM_DEBUG("dev_priv->prim_head : %p\n", dev_priv->prim_head); + printk("dev_priv->prim_head : %p\n", dev_priv->prim_head); dev_priv->current_dma_ptr = dev_priv->prim_head; dev_priv->prim_num_dwords = 0; dev_priv->prim_max_dwords = dev_priv->primary_size / 4; - DRM_DEBUG("dma initialization\n"); + printk("dma initialization\n"); /* Private is now filled in, initialize the hardware */ { @@ -183,7 +245,7 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { /* Poll for the first buffer to insure that * the status register will be correct */ - DRM_DEBUG("phys_head : %lx\n", phys_head); + printk("phys_head : %lx\n", phys_head); MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); @@ -204,7 +266,7 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { } - DRM_DEBUG("dma init was successful\n"); + printk("dma init was successful\n"); return 0; } @@ -238,6 +300,7 @@ static void __mga_iload_small(drm_device_t *dev, { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_buf_priv_t *buf_priv = buf->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned long address = (unsigned long)buf->bus_address; int length = buf->used; int y1 = buf_priv->boxes[0].y1; @@ -289,6 +352,7 @@ static void __mga_iload_xy(drm_device_t *dev, { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_buf_priv_t *buf_priv = buf->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned long address = (unsigned long)buf->bus_address; int length = buf->used; int y1 = buf_priv->boxes[0].y1; @@ -366,10 +430,10 @@ static void mga_dma_dispatch_iload(drm_device_t *dev, drm_buf_t *buf) int x2 = buf_priv->boxes[0].x2; if((x2 - x1) < 32) { - DRM_DEBUG("using iload small\n"); + printk("using iload small\n"); __mga_iload_small(dev, buf, use_agp); } else { - DRM_DEBUG("using iload xy\n"); + printk("using iload xy\n"); __mga_iload_xy(dev, buf, use_agp); } } @@ -465,8 +529,12 @@ static inline void mga_dma_quiescent(drm_device_t *dev) } } while((MGA_READ(MGAREG_STATUS) & 0x00020001) != 0x00020000) ; - MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); - while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; +#if 0 + MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); +#endif + while(MGA_READ(MGAREG_DWGSYNC) == MGA_SYNC_TAG) ; + MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); + while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; atomic_dec(&dev_priv->dispatch_lock); } @@ -537,6 +605,7 @@ static int mga_do_dma(drm_device_t *dev, int locked) drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_mga_buf_priv_t *buf_priv; + printk("mga_do_dma\n"); if (test_and_set_bit(0, &dev->dma_flag)) { atomic_inc(&dma->total_missed_dma); return -EBUSY; @@ -550,7 +619,7 @@ static int mga_do_dma(drm_device_t *dev, int locked) buf = dma->next_buffer; - DRM_DEBUG("context %d, buffer %d\n", buf->context, buf->idx); + printk("context %d, buffer %d\n", buf->context, buf->idx); if (buf->list == DRM_LIST_RECLAIM) { drm_clear_next_buffer(dev); @@ -581,8 +650,8 @@ static int mga_do_dma(drm_device_t *dev, int locked) atomic_dec(&dev_priv->dispatch_lock); return -EBUSY; } - + dma->next_queue = dev->queuelist[DRM_KERNEL_CONTEXT]; drm_clear_next_buffer(dev); buf->pending = 1; buf->waiting = 0; @@ -590,6 +659,7 @@ static int mga_do_dma(drm_device_t *dev, int locked) buf_priv = buf->dev_private; + printk("dispatch!\n"); switch (buf_priv->dma_type) { case MGA_DMA_GENERAL: mga_dma_dispatch_general(dev, buf); @@ -604,9 +674,10 @@ static int mga_do_dma(drm_device_t *dev, int locked) mga_dma_dispatch_iload(dev, buf); break; default: - DRM_DEBUG("bad buffer type %x in dispatch\n", buf_priv->dma_type); + printk("bad buffer type %x in dispatch\n", buf_priv->dma_type); break; } + atomic_dec(&dev_priv->pending_bufs); drm_free_buffer(dev, dma->this_buffer); dma->this_buffer = buf; @@ -622,19 +693,25 @@ static int mga_do_dma(drm_device_t *dev, int locked) } clear_bit(0, &dev->dma_flag); - + + if(!atomic_read(&dev_priv->pending_bufs)) { + wake_up_interruptible(&dev->queuelist[DRM_KERNEL_CONTEXT]->flush_queue); + } + +#if 0 + wake_up_interruptible(&dev->lock.lock_queue); +#endif + /* We hold the dispatch lock until the interrupt handler * frees it */ return retcode; } -/* static void mga_dma_schedule_timer_wrapper(unsigned long dev) { mga_dma_schedule((drm_device_t *)dev, 0); } -*/ static void mga_dma_schedule_tq_wrapper(void *dev) { @@ -651,6 +728,8 @@ int mga_dma_schedule(drm_device_t *dev, int locked) int expire = 20; drm_device_dma_t *dma = dev->dma; + printk("mga_dma_schedule\n"); + if (test_and_set_bit(0, &dev->interrupt_flag)) { /* Not reentrant */ atomic_inc(&dma->total_missed_sched); @@ -658,7 +737,6 @@ int mga_dma_schedule(drm_device_t *dev, int locked) } missed = atomic_read(&dma->total_missed_sched); - again: /* There is only one queue: */ @@ -696,11 +774,10 @@ again: } clear_bit(0, &dev->interrupt_flag); + return retcode; } - - int mga_irq_install(drm_device_t *dev, int irq) { int retcode; @@ -715,7 +792,7 @@ int mga_irq_install(drm_device_t *dev, int irq) dev->irq = irq; up(&dev->struct_sem); - DRM_DEBUG("install irq handler %d\n", irq); + printk("install irq handler %d\n", irq); dev->context_flag = 0; dev->interrupt_flag = 0; @@ -762,7 +839,7 @@ int mga_irq_uninstall(drm_device_t *dev) if (!irq) return -EINVAL; - DRM_DEBUG("remove irq handler %d\n", irq); + printk("remove irq handler %d\n", irq); MGA_WRITE(MGAREG_ICLEAR, 0xfa7); MGA_WRITE(MGAREG_IEN, 0); @@ -793,6 +870,36 @@ int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, } } +int mga_flush_queue(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_queue_t *q = dev->queuelist[DRM_KERNEL_CONTEXT]; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + int ret = 0; + + printk("mga_flush_queue\n"); + if(atomic_read(&dev_priv->pending_bufs) != 0) { + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&q->flush_queue, &entry); + for (;;) { + if (!atomic_read(&dev_priv->pending_bufs)) break; + printk("Calling schedule from flush_queue : %d\n", + atomic_read(&dev_priv->pending_bufs)); + mga_dma_schedule(dev, 1); + schedule(); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + break; + } + } + printk("Exited out of schedule from flush_queue\n"); + current->state = TASK_RUNNING; + remove_wait_queue(&q->flush_queue, &entry); + } + + return ret; +} + int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -810,50 +917,62 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, return -EINVAL; } - DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + printk("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", lock.context, current->pid, dev->lock.hw_lock->lock, lock.flags); - if (lock.context < 0 || lock.context >= dev->queue_count) { + if (lock.context < 0) { return -EINVAL; } - - for (;;) { - if (!dev->lock.hw_lock) { /* Device has been unregistered */ - ret = -EINTR; - break; - } + /* Only one queue: + */ - if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) { - dev->lock.pid = current->pid; - dev->lock.lock_time = jiffies; - atomic_inc(&dev->total_locks); - break; /* Got lock */ - } + if (!ret) { + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + ret = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + lock.context)) { + dev->lock.pid = current->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } - /* Contention */ - atomic_inc(&dev->total_sleeps); - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + current->policy |= SCHED_YIELD; + printk("Calling lock schedule\n"); + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); } - - current->state = TASK_RUNNING; - remove_wait_queue(&dev->lock.lock_queue, &entry); if (!ret) { if (lock.flags & _DRM_LOCK_QUIESCENT) { - DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); - drm_flush_queue(dev, DRM_KERNEL_CONTEXT); - drm_flush_unblock_queue(dev, DRM_KERNEL_CONTEXT); - mga_dma_quiescent(dev); + printk("_DRM_LOCK_QUIESCENT\n"); + ret = mga_flush_queue(dev); + if(ret != 0) { + drm_lock_free(dev, &dev->lock.hw_lock->lock, + lock.context); + } else { + mga_dma_quiescent(dev); + } } } - DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + printk("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); return ret; } + diff --git a/linux/mga_dma.h b/linux/mga_dma.h index 958756a4..7f1c5795 100644 --- a/linux/mga_dma.h +++ b/linux/mga_dma.h @@ -67,7 +67,7 @@ typedef struct { -#define VERBO 1 +#define VERBO 0 /* Primary buffer versions of above -- pretty similar really. diff --git a/linux/mga_drv.c b/linux/mga_drv.c index 583afe77..edd60148 100644 --- a/linux/mga_drv.c +++ b/linux/mga_drv.c @@ -80,13 +80,13 @@ static drm_ioctl_desc_t mga_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { mga_mapbufs, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { mga_freebufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { drm_addctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { drm_rmctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { drm_modctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { drm_getctx, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { drm_newctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { drm_resctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { mga_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { mga_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { mga_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { mga_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { mga_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { mga_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { mga_resctx, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 }, @@ -571,6 +571,6 @@ int mga_unlock(struct inode *inode, struct file *filp, unsigned int cmd, DRM_KERNEL_CONTEXT)) { DRM_ERROR("\n"); } - + return 0; } diff --git a/linux/mga_drv.h b/linux/mga_drv.h index 3dd50827..ef299978 100644 --- a/linux/mga_drv.h +++ b/linux/mga_drv.h @@ -52,6 +52,7 @@ typedef struct _drm_mga_private { mgaWarpIndex WarpIndex[MGA_MAX_G400_PIPES]; __volatile__ unsigned long softrap_age; atomic_t dispatch_lock; + atomic_t pending_bufs; void *ioremap; u32 *prim_head; u32 *current_dma_ptr; @@ -123,6 +124,24 @@ extern int mga_swap_bufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int mga_iload(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); + /* mga_context.c */ +extern int mga_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int mga_context_switch(drm_device_t *dev, int old, int new); +extern int mga_context_switch_complete(drm_device_t *dev, int new); |