diff options
author | Jeff Hartmann <jhartmann@valinux.com> | 2000-02-21 01:37:50 +0000 |
---|---|---|
committer | Jeff Hartmann <jhartmann@valinux.com> | 2000-02-21 01:37:50 +0000 |
commit | 5ae11234d9f7701289254c662a29a6f16914b389 (patch) | |
tree | 4e77d373640849e435934fb0d1869c0ec2e40361 | |
parent | 4f4242d4c87088b71eb3bee2cb95b51c860b9cad (diff) |
Added multiple outstanding dma requests for the mga
-rw-r--r-- | linux-core/i810_dma.c | 37 | ||||
-rw-r--r-- | linux/Makefile.linux | 3 | ||||
-rw-r--r-- | linux/i810_dma.c | 37 | ||||
-rw-r--r-- | linux/mga_context.c | 44 | ||||
-rw-r--r-- | linux/mga_dma.c | 1439 | ||||
-rw-r--r-- | linux/mga_dma.h | 153 | ||||
-rw-r--r-- | linux/mga_drm_public.h | 4 | ||||
-rw-r--r-- | linux/mga_drv.h | 38 | ||||
-rw-r--r-- | linux/mga_state.c | 679 |
9 files changed, 1066 insertions, 1368 deletions
diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 4d431a18..c374493a 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -104,31 +104,16 @@ static drm_buf_t *i810_freelist_get(drm_device_t *dev) /* Linear search might not be the best solution */ -#if 0 - i810_print_status_page(dev); -#endif for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; /* In use is already a pointer */ -#if 0 - printk("idx : %d in_use : %d\n", i, *buf_priv->in_use); -#endif used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, I810_BUF_USED); -#if 0 - printk("used : %d\n", used); -#endif if(used == I810_BUF_FREE) { -#if 0 - printk("Got buffer\n"); -#endif return buf; } } -#if 0 - printk("Didn't get buffer\n"); -#endif return NULL; } @@ -142,9 +127,6 @@ static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf) int used; /* In use is already a pointer */ -#if 0 - i810_print_status_page(dev); -#endif used = cmpxchg(buf_priv->in_use, I810_BUF_USED, I810_BUF_FREE); if(used != I810_BUF_USED) { DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); @@ -300,9 +282,6 @@ static int i810_freelist_init(drm_device_t *dev) buf_priv->my_use_idx = my_idx; my_idx += 4; } -#if 0 - i810_print_status_page(dev); -#endif return 0; } @@ -495,10 +474,7 @@ static inline void i810_dma_dispatch_vertex(drm_device_t *dev, drm_buf_t *buf) static inline void i810_dma_quiescent(drm_device_t *dev) { -#if 0 /* Not written yet */ - drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; -#endif } /* Interrupts are only for flushing */ @@ -600,9 +576,7 @@ int i810_irq_uninstall(drm_device_t *dev) if (!irq) return -EINVAL; - DRM_DEBUG( "Interrupt UnInstall: %d\n", irq); - - + DRM_DEBUG( "Interrupt UnInstall: %d\n", irq); DRM_DEBUG("%d\n", irq); temp = I810_READ16(I810REG_INT_IDENTITY_R); @@ -669,16 +643,10 @@ static int i810_flush_queue(drm_device_t *dev) drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; int ret = 0; -#if 0 - printk("i810_flush_queue\n"); -#endif if(dev_priv == NULL) { return 0; } atomic_set(&dev_priv->flush_done, 0); -#if 0 - printk("got to flush\n"); -#endif current->state = TASK_INTERRUPTIBLE; add_wait_queue(&dev_priv->flush_queue, &entry); for (;;) { @@ -779,9 +747,6 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; -#if 0 - current->policy |= SCHED_YIELD; -#endif DRM_DEBUG("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { diff --git a/linux/Makefile.linux b/linux/Makefile.linux index 41f7a7db..f740220f 100644 --- a/linux/Makefile.linux +++ b/linux/Makefile.linux @@ -71,8 +71,7 @@ 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 \ - mga_context.o +MGAOBJS= mga_drv.o mga_dma.o mga_bufs.o mga_state.o mga_context.o MGAHEADERS= mga_drv.h mga_drm_public.h $(DRMHEADERS) R128OBJS= r128_drv.o r128_context.o diff --git a/linux/i810_dma.c b/linux/i810_dma.c index 4d431a18..c374493a 100644 --- a/linux/i810_dma.c +++ b/linux/i810_dma.c @@ -104,31 +104,16 @@ static drm_buf_t *i810_freelist_get(drm_device_t *dev) /* Linear search might not be the best solution */ -#if 0 - i810_print_status_page(dev); -#endif for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; /* In use is already a pointer */ -#if 0 - printk("idx : %d in_use : %d\n", i, *buf_priv->in_use); -#endif used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, I810_BUF_USED); -#if 0 - printk("used : %d\n", used); -#endif if(used == I810_BUF_FREE) { -#if 0 - printk("Got buffer\n"); -#endif return buf; } } -#if 0 - printk("Didn't get buffer\n"); -#endif return NULL; } @@ -142,9 +127,6 @@ static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf) int used; /* In use is already a pointer */ -#if 0 - i810_print_status_page(dev); -#endif used = cmpxchg(buf_priv->in_use, I810_BUF_USED, I810_BUF_FREE); if(used != I810_BUF_USED) { DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); @@ -300,9 +282,6 @@ static int i810_freelist_init(drm_device_t *dev) buf_priv->my_use_idx = my_idx; my_idx += 4; } -#if 0 - i810_print_status_page(dev); -#endif return 0; } @@ -495,10 +474,7 @@ static inline void i810_dma_dispatch_vertex(drm_device_t *dev, drm_buf_t *buf) static inline void i810_dma_quiescent(drm_device_t *dev) { -#if 0 /* Not written yet */ - drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; -#endif } /* Interrupts are only for flushing */ @@ -600,9 +576,7 @@ int i810_irq_uninstall(drm_device_t *dev) if (!irq) return -EINVAL; - DRM_DEBUG( "Interrupt UnInstall: %d\n", irq); - - + DRM_DEBUG( "Interrupt UnInstall: %d\n", irq); DRM_DEBUG("%d\n", irq); temp = I810_READ16(I810REG_INT_IDENTITY_R); @@ -669,16 +643,10 @@ static int i810_flush_queue(drm_device_t *dev) drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; int ret = 0; -#if 0 - printk("i810_flush_queue\n"); -#endif if(dev_priv == NULL) { return 0; } atomic_set(&dev_priv->flush_done, 0); -#if 0 - printk("got to flush\n"); -#endif current->state = TASK_INTERRUPTIBLE; add_wait_queue(&dev_priv->flush_queue, &entry); for (;;) { @@ -779,9 +747,6 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd, /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; -#if 0 - current->policy |= SCHED_YIELD; -#endif DRM_DEBUG("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { diff --git a/linux/mga_context.c b/linux/mga_context.c index 4e793213..aadc846e 100644 --- a/linux/mga_context.c +++ b/linux/mga_context.c @@ -194,51 +194,11 @@ int mga_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, 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); + if(ctx.handle != DRM_KERNEL_CONTEXT) { + drm_ctxbitmap_free(dev, ctx.handle); } return 0; diff --git a/linux/mga_dma.c b/linux/mga_dma.c index a424e2f6..ec9df633 100644 --- a/linux/mga_dma.c +++ b/linux/mga_dma.c @@ -36,7 +36,6 @@ #include "mga_drv.h" #include "mgareg_flags.h" #include "mga_dma.h" -#include "mga_state.h" #include <linux/interrupt.h> /* For task queue support */ @@ -47,20 +46,8 @@ #define MGA_DEREF(reg) *(__volatile__ int *)MGA_ADDR(reg) #define MGA_READ(reg) MGA_DEREF(reg) #define MGA_WRITE(reg,val) do { MGA_DEREF(reg) = val; } while (0) -#define MGA_DEREF8(reg) *(__volatile__ u8 *)MGA_ADDR(reg) -#define MGA_READ8(reg) MGA_DEREF8(reg) -#define MGA_WRITE8(reg,val) do { MGA_DEREF8(reg) = val; } while (0) #define PDEA_pagpxfer_enable 0x2 -#define MGA_TOP_SYNC_TAG 0x3784f700 -#define MGA_SYNC_TAG 0x423f4200 - -typedef enum { - TT_GENERAL, - TT_BLIT, - TT_VECTOR, - TT_VERTEX -} transferType_t; static unsigned long mga_alloc_page(drm_device_t *dev) { @@ -96,11 +83,320 @@ static void mga_delay(void) static void mga_flush_write_combine(void) { int xchangeDummy; - __asm__ volatile( " push %%eax ; xchg %%eax, %0 ; pop %%eax" : : "m" (xchangeDummy)); + __asm__ volatile(" push %%eax ; xchg %%eax, %0 ; pop %%eax" : : "m" (xchangeDummy)); __asm__ volatile(" push %%eax ; push %%ebx ; push %%ecx ; push %%edx ;" " movl $0,%%eax ; cpuid ; pop %%edx ; pop %%ecx ; pop %%ebx ;" " pop %%eax" : /* no outputs */ : /* no inputs */ ); } +/* These are two age tags that will never be sent to + * the hardware */ +#define MGA_BUF_USED 0xffffffff +#define MGA_BUF_FREE 0 + +static void mga_freelist_init(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + + buf_priv->age = MGA_BUF_FREE; + } +} + +unsigned int mga_create_sync_tag(drm_mga_private_t *dev_priv) +{ + unsigned int temp; + + dev_priv->sync_tag++; + if(dev_priv->sync_tag > 0x3fffffff) { + /* Make sure we are always at least 1 */ + dev_priv->sync_tag = 1; + /* Do a full dma flush */ + } + temp = dev_priv->sync_tag << 2; + DRM_DEBUG("sync_tag : %x\n", temp); + return temp; +} + +drm_buf_t *mga_freelist_get(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + int i; + + /* Linear search might not be the best solution */ + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + if(buf_priv->age < status[1]) { + buf_priv->age = MGA_BUF_USED; + return buf; + } + } + return NULL; +} + +int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf) +{ + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + + /* In use is already a pointer */ + if(buf_priv->age != MGA_BUF_USED) { + DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); + return -EINVAL; + } + buf_priv->age = MGA_BUF_FREE; + + return 0; +} + +static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_prim_buf_t *prim_buffer; + int i, temp, size_of_buf; + int offset = init->reserved_map_agpstart; + + DRM_DEBUG("mga_init_primary_bufs\n"); + dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / + PAGE_SIZE) * PAGE_SIZE; + DRM_DEBUG("primary_size\n"); + size_of_buf = dev_priv->primary_size / MGA_NUM_PRIM_BUFS; + dev_priv->warp_ucode_size = init->warp_ucode_size; + dev_priv->prim_bufs = drm_alloc(sizeof(drm_mga_prim_buf_t *) * + (MGA_NUM_PRIM_BUFS + 1), + DRM_MEM_DRIVER); + if(dev_priv->prim_bufs == NULL) { + DRM_ERROR("Unable to allocate memory for prim_buf\n"); + return -ENOMEM; + } + DRM_DEBUG("memset\n"); + memset(dev_priv->prim_bufs, + 0, sizeof(drm_mga_prim_buf_t *) * (MGA_NUM_PRIM_BUFS + 1)); + + 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); + /* Make sure that ioremap is u8 type */ + DRM_DEBUG("ioremap\n"); + dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, + temp); + if(dev_priv->ioremap == NULL) { + DRM_DEBUG("Ioremap failed\n"); + return -ENOMEM; + } + init_waitqueue_head(&dev_priv->wait_queue); + + for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { + DRM_DEBUG("For loop\n"); + prim_buffer = drm_alloc(sizeof(drm_mga_prim_buf_t), DRM_MEM_DRIVER); + if(prim_buffer == NULL) return -ENOMEM; + DRM_DEBUG("memset\n"); + memset(prim_buffer, 0, sizeof(drm_mga_prim_buf_t)); + prim_buffer->phys_head = offset + dev->agp->base; + prim_buffer->current_dma_ptr = prim_buffer->head = (u32 *) + (dev_priv->ioremap + (offset - init->reserved_map_agpstart)); + prim_buffer->num_dwords = 0; + prim_buffer->max_dwords = size_of_buf / sizeof(u32); + prim_buffer->max_dwords -= 5; /* Leave room for the softrap */ + prim_buffer->sec_used = 0; + prim_buffer->idx = i; + offset = offset + size_of_buf; + dev_priv->prim_bufs[i] = prim_buffer; + DRM_DEBUG("Looping\n"); + } + dev_priv->current_prim_idx = 0; + dev_priv->next_prim = dev_priv->last_prim = dev_priv->current_prim = + dev_priv->prim_bufs[0]; + set_bit(0, &dev_priv->current_prim->in_use); + DRM_DEBUG("init done\n"); + return 0; +} + +void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + int use_agp = PDEA_pagpxfer_enable; + PRIMLOCALS; + + dev_priv->last_sync_tag = mga_create_sync_tag(dev_priv); + + /* We never check for overflow, b/c there is always room */ + PRIMPTR(prim); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMOUTREG( MGAREG_SOFTRAP, prim->idx << 2); + PRIMFINISH(prim); + + if(sarea_priv->dirty & MGA_DMA_FLUSH) { + /* This needs to be optimized so that it only happens + * when the Xserver actually did 2d rendering */ + DRM_DEBUG("Dma top flush\n"); + while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) ; + sarea_priv->dirty &= ~(MGA_DMA_FLUSH); + } else { + DRM_DEBUG("Status wait\n"); + while((MGA_READ(MGAREG_STATUS) & 0x00020001) != 0x00020000) ; + } + + mga_flush_write_combine(); + MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); + MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); +} + +int mga_advance_primary(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_prim_buf_t *prim_buffer; + int next_prim_idx; + int ret = 0; + + /* This needs to reset the primary buffer if available, + * we should collect stats on how many times it bites + * it's tail */ + next_prim_idx = dev_priv->current_prim_idx + 1; + if(next_prim_idx >= MGA_NUM_PRIM_BUFS) + next_prim_idx = 0; + prim_buffer = dev_priv->prim_bufs[next_prim_idx]; + /* In use is cleared in interrupt handler */ + atomic_set(&dev_priv->in_wait, 1); + if(test_and_set_bit(0, &prim_buffer->in_use)) { + /* We need to wait, we should probably use + * a wait queue for this. + */ + add_wait_queue(&dev_priv->wait_queue, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if(!test_and_set_bit(0, &prim_buffer->in_use)) break; + atomic_inc(&dev->total_sleeps); + mga_dma_schedule(dev, 0); + schedule_timeout(HZ/60); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->wait_queue, &entry); + if(ret) return ret; + } + atomic_set(&dev_priv->in_wait, 0); + /* This primary buffer is now free to use */ + prim_buffer->current_dma_ptr = prim_buffer->head; + prim_buffer->num_dwords = 0; + prim_buffer->sec_used = 0; + dev_priv->current_prim = prim_buffer; + dev_priv->current_prim_idx = next_prim_idx; + return 0; +} + +int mga_dma_schedule(drm_device_t *dev, int locked) +{ + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_device_dma_t *dma = dev->dma; + + if (test_and_set_bit(0, &dev->dma_flag)) { + atomic_inc(&dma->total_missed_dma); + return -EBUSY; + } + + if (!locked && !atomic_read(&dev_priv->in_flush) && + !atomic_read(&dev_priv->in_wait) && + !drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + atomic_inc(&dma->total_missed_lock); + clear_bit(0, &dev->dma_flag); + return -EBUSY; + } + + if(!test_and_set_bit(0, &dev_priv->dispatch_lock)) { + /* Fire dma buffer */ + if(dev_priv->next_prim->sec_used >= (MGA_DMA_BUF_NR / 2) || + (dev_priv->next_prim->num_dwords && atomic_read(&dev_priv->in_flush)) || + atomic_read(&dev_priv->next_prim->force_fire)) { + DRM_DEBUG("mga_fire_primary\n"); + atomic_set(&dev_priv->next_prim->force_fire, 0); + if(dev_priv->current_prim == dev_priv->next_prim) { + mga_advance_primary(dev); + } + mga_fire_primary(dev, + dev_priv->next_prim); + DRM_DEBUG("idx :%d\n", dev_priv->next_prim->idx); + } else { + clear_bit(0, &dev_priv->dispatch_lock); + } + } + + if (!locked && !atomic_read(&dev_priv->in_flush) + && !atomic_read(&dev_priv->in_wait)) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } + + clear_bit(0, &dev->dma_flag); + return 0; +} + +static void mga_dma_service(int irq, void *device, struct pt_regs *regs) +{ + drm_device_t *dev = (drm_device_t *)device; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_prim_buf_t *last_prim_buffer; + int softrap_idx; + int next_idx; + + softrap_idx = MGA_READ(MGAREG_SECADDRESS); + atomic_inc(&dev->total_irq); + MGA_WRITE(MGAREG_ICLEAR, 0x00000001); + softrap_idx = softrap_idx >> 2; + DRM_DEBUG("softrap_idx : %d\n", softrap_idx); + next_idx = softrap_idx + 1; + if(next_idx >= MGA_NUM_PRIM_BUFS) { + next_idx = 0; + } + dev_priv->next_prim = dev_priv->prim_bufs[next_idx]; + last_prim_buffer = dev_priv->prim_bufs[softrap_idx]; + dev_priv->last_prim = last_prim_buffer; + last_prim_buffer->num_dwords = 0; + clear_bit(0, &last_prim_buffer->in_use); + clear_bit(0, &dev_priv->dispatch_lock); + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void mga_dma_task_queue(void *device) +{ + /* This needs to do primary buffer ping-ponging as well + * as flushing */ + drm_device_t *dev = (drm_device_t *) device; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + + wake_up_interruptible(&dev_priv->wait_queue); + mga_dma_schedule(dev, 0); + if(atomic_read(&dev_priv->in_flush) == 1 && + dev_priv->next_prim->num_dwords == 0) { + /* Everything is on the hardware */ + atomic_set(&dev_priv->in_flush, 0); + wake_up_interruptible(&dev_priv->flush_queue); + } +} int mga_dma_cleanup(drm_device_t *dev) { @@ -121,6 +417,20 @@ int mga_dma_cleanup(drm_device_t *dev) if(dev_priv->real_status_page != 0UL) { mga_free_page(dev, dev_priv->real_status_page); } + if(dev_priv->prim_bufs != NULL) { + int i; + for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { + if(dev_priv->prim_bufs[i] != NULL) { + drm_free(dev_priv->prim_bufs[i], + sizeof(drm_mga_prim_buf_t), + DRM_MEM_DRIVER); + } + } + drm_free(dev_priv->prim_bufs, sizeof(void *) * + (MGA_NUM_PRIM_BUFS + 1), + DRM_MEM_DRIVER); + } + drm_free(dev->dev_private, sizeof(drm_mga_private_t), DRM_MEM_DRIVER); @@ -130,80 +440,9 @@ int mga_dma_cleanup(drm_device_t *dev) 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]; - DRM_DEBUG("Kernel queue already allocated\n"); - } else { - queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES); - if(!queue) { - up(&dev->struct_sem); - DRM_DEBUG("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); - DRM_DEBUG("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); - DRM_DEBUG("%d (new)\n", dev->queue_count - 1); - return DRM_KERNEL_CONTEXT; -} - -static unsigned int mga_create_sync_tag(drm_mga_private_t *dev_priv) -{ - unsigned int temp; - - dev_priv->sync_tag++; - temp = dev_priv->sync_tag << 2; - DRM_DEBUG("sync_tag : %x\n", temp); - return temp; -} - 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; drm_map_t *sarea_map = NULL; - int temp; int i; dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); @@ -213,7 +452,6 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { DRM_DEBUG("dev_private\n"); memset(dev_priv, 0, sizeof(drm_mga_private_t)); - atomic_set(&dev_priv->pending_bufs, 0); atomic_set(&dev_priv->in_flush, 0); if((init->reserved_map_idx >= dev->map_count) || @@ -223,12 +461,6 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { return -EINVAL; } - if(mga_alloc_kernel_queue(dev) != DRM_KERNEL_CONTEXT) { - mga_dma_cleanup(dev); - DRM_ERROR("Kernel context queue not present\n"); - return -ENOMEM; - } - dev_priv->reserved_map_idx = init->reserved_map_idx; dev_priv->buffer_map_idx = init->buffer_map_idx; sarea_map = dev->maplist[0]; @@ -238,9 +470,6 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { DRM_DEBUG("sarea_priv\n"); /* Scale primary size to the next page */ - dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / - PAGE_SIZE) * PAGE_SIZE; - dev_priv->warp_ucode_size = init->warp_ucode_size; dev_priv->chipset = init->chipset; dev_priv->frontOffset = init->frontOffset; dev_priv->backOffset = init->backOffset; @@ -252,58 +481,33 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { dev_priv->stride = init->stride; dev_priv->mAccess = init->mAccess; - + init_waitqueue_head(&dev_priv->flush_queue); dev_priv->WarpPipe = -1; - if (MGA_VERBOSE) { - DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n", + DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n", dev_priv->chipset, dev_priv->warp_ucode_size, dev_priv->backOffset, dev_priv->depthOffset); - DRM_DEBUG("cpp: %d sgram: %d stride: %d maccess: %x\n", + DRM_DEBUG("cpp: %d sgram: %d stride: %d maccess: %x\n", dev_priv->cpp, dev_priv->sgram, dev_priv->stride, dev_priv->mAccess); - } - memcpy(&dev_priv->WarpIndex, &init->WarpIndex, sizeof(mgaWarpIndex) * MGA_MAX_WARP_PIPES); - if (MGA_VERBOSE) - for (i = 0 ; i < MGA_MAX_WARP_PIPES ; i++) - DRM_DEBUG("warp pipe %d: installed: %d phys_addr: %lx size: %x\n", - i, - dev_priv->WarpIndex[i].installed, - dev_priv->WarpIndex[i].phys_addr, - dev_priv->WarpIndex[i].size); - - - 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; - - if (MGA_VERBOSE) { - 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); - } + for (i = 0 ; i < MGA_MAX_WARP_PIPES ; i++) + DRM_DEBUG("warp pipe %d: installed: %d phys_addr: %lx size: %x\n", + i, + dev_priv->WarpIndex[i].installed, + dev_priv->WarpIndex[i].phys_addr, + dev_priv->WarpIndex[i].size); - dev_priv->ioremap = drm_ioremap(dev->agp->base + init->reserved_map_agpstart, - temp); - if(dev_priv->ioremap == NULL) { - DRM_DEBUG("Ioremap failed\n"); - mga_dma_cleanup(dev); - return -ENOMEM; + DRM_DEBUG("Doing init prim buffers\n"); + if(mga_init_primary_bufs(dev, init) != 0) { + DRM_ERROR("Can not initialize primary buffers\n"); + mga_dma_cleanup(dev); + return -ENOMEM; } - - - - dev_priv->prim_head = (u32 *)dev_priv->ioremap; - 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("Done with init prim buffers\n"); dev_priv->real_status_page = mga_alloc_page(dev); if(dev_priv->real_status_page == 0UL) { mga_dma_cleanup(dev); @@ -330,16 +534,12 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { return -EINVAL; } - - if (MGA_VERBOSE) - DRM_DEBUG("dma initialization\n"); + DRM_DEBUG("dma initialization\n"); /* Private is now filled in, initialize the hardware */ { __volatile__ unsigned int *status = (unsigned int *)dev_priv->status_page; PRIMLOCALS; - PRIMRESET( dev_priv ); - PRIMGETPTR( dev_priv ); dev_priv->last_sync_tag = mga_create_sync_tag(dev_priv); @@ -348,16 +548,15 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DWGSYNC, dev_priv->last_sync_tag); PRIMOUTREG(MGAREG_SOFTRAP, 0); - +/* PRIMADVANCE( dev_priv ); - +*/ /* Poll for the first buffer to insure that * the status register will be correct */ DRM_DEBUG("phys_head : %lx\n", (unsigned long)phys_head); status[1] = 0; - mga_flush_write_combine(); MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); @@ -367,12 +566,12 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { while(MGA_READ(MGAREG_DWGSYNC) != dev_priv->last_sync_tag) ; DRM_DEBUG("status[0] after initialization : %x\n", status[0]); DRM_DEBUG("status[1] after initialization : %x\n", status[1]); - DRM_DEBUG("status[2] after initialization : %x\n", status[2]); - DRM_DEBUG("status[3] after initialization : %x\n", status[3]); + /* Reset the buffer structure */ + } - - if (MGA_VERBOSE) - DRM_DEBUG("dma init was successful\n"); + + mga_freelist_init(dev); + DRM_DEBUG("dma init was successful\n"); return 0; } @@ -395,359 +594,6 @@ int mga_dma_init(struct inode *inode, struct file *filp, return -EINVAL; } - -#if 0 -static void __mga_iload_small(drm_device_t *dev, drm_buf_t *buf) -{ - int use_agp = PDEA_pagpxfer_enable; - 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; - int x1 = buf_priv->boxes[0].x1; - int y2 = buf_priv->boxes[0].y2; - int x2 = buf_priv->boxes[0].x2; - int dstorg = buf_priv->ContextState[MGA_CTXREG_DSTORG]; - int maccess = buf_priv->ContextState[MGA_CTXREG_MACCESS]; - PRIMLOCALS; - - PRIMRESET(dev_priv); - PRIMGETPTR(dev_priv); - - dev_priv->last_sync_tag = mga_create_sync_tag(dev_priv); - - PRIMOUTREG(MGAREG_DSTORG, dstorg ); - PRIMOUTREG(MGAREG_MACCESS, maccess); - PRIMOUTREG(MGAREG_PITCH, (1 << 15)); - PRIMOUTREG(MGAREG_YDST, y1 * (x2 - x1)); - - PRIMOUTREG(MGAREG_LEN, 1); - PRIMOUTREG(MGAREG_FXBNDRY, ((x2 - x1) * (y2 - y1) - 1) << 16); - PRIMOUTREG(MGAREG_AR0, (x2 - x1) * (y2 - y1) - 1); - PRIMOUTREG(MGAREG_AR3, 0); - - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, MGA_ILOAD_CMD); - - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_SECADDRESS, ((__u32)address) | TT_BLIT); - PRIMOUTREG(MGAREG_SECEND, ((__u32)(address + length)) | use_agp); - - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, dev_priv->last_sync_tag); - PRIMOUTREG(MGAREG_SOFTRAP, 0); - - PRIMADVANCE(dev_priv); -#if 0 - /* For now we need to set this in the ioctl */ - sarea_priv->dirty |= MGASAREA_NEW_CONTEXT; -#endif - - if(sarea_priv->dirty & MGA_DMA_FLUSH) { - DRM_DEBUG("Dma top flush\n"); - while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) ; - sarea_priv->dirty &= ~(MGA_DMA_FLUSH); - } - - PRIMADVANCE(dev_priv); - mga_flush_write_combine(); - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); -} - -static void __mga_iload_xy(drm_device_t *dev, drm_buf_t *buf ) -{ - int use_agp = PDEA_pagpxfer_enable; - 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; - int x1 = buf_priv->boxes[0].x1; - int y2 = buf_priv->boxes[0].y2; - int x2 = buf_priv->boxes[0].x2; - int dstorg = buf_priv->ContextState[MGA_CTXREG_DSTORG]; - int maccess = buf_priv->ContextState[MGA_CTXREG_MACCESS]; - int pitch = buf_priv->ServerState[MGA_2DREG_PITCH]; - int width, height; - int texperdword = 0; - PRIMLOCALS; - - width = (x2 - x1); - height = (y2 - y1); - switch((maccess & 0x00000003)) { - case 0: - texperdword = 4; - break; - case 1: - texperdword = 2; - break; - case 2: - texperdword = 1; - break; - default: - DRM_ERROR("Invalid maccess value passed to __mga_iload_xy\n"); - return; - } - - x2 = x1 + width; - x2 = (x2 + (texperdword - 1)) & ~(texperdword - 1); - x1 = (x1 + (texperdword - 1)) & ~(texperdword - 1); - width = x2 - x1; - - dev_priv->last_sync_tag = mga_create_sync_tag(dev_priv); - - PRIMRESET(dev_priv); - PRIMGETPTR(dev_priv); - PRIMOUTREG(MGAREG_DSTORG, dstorg); - PRIMOUTREG(MGAREG_MACCESS, maccess); - PRIMOUTREG(MGAREG_PITCH, pitch); - PRIMOUTREG(MGAREG_YDSTLEN, (y1 << 16) | height); - - PRIMOUTREG(MGAREG_FXBNDRY, ((x1+width-1) << 16) | x1); - PRIMOUTREG(MGAREG_AR0, width * height - 1); - PRIMOUTREG(MGAREG_AR3, 0 ); - PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, MGA_ILOAD_CMD); - - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_SECADDRESS, ((__u32)address) | TT_BLIT); - PRIMOUTREG(MGAREG_SECEND, ((__u32)(address + length)) | use_agp); - - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, dev_priv->last_sync_tag); - PRIMOUTREG(MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); -#if 0 - /* For now we need to set this in the ioctl */ - sarea_priv->dirty |= MGASAREA_NEW_CONTEXT; -#endif - if(sarea_priv->dirty & MGA_DMA_FLUSH) { - DRM_DEBUG("Dma top flush\n"); - while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) ; - sarea_priv->dirty &= ~(MGA_DMA_FLUSH); - } - - mga_flush_write_combine(); - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); -} - - -static void mga_dma_dispatch_iload(drm_device_t *dev, drm_buf_t *buf) -{ - drm_mga_buf_priv_t *buf_priv = buf->dev_private; - - int x1 = buf_priv->boxes[0].x1; - int x2 = buf_priv->boxes[0].x2; - - - if((x2 - x1) < 32) { - if (MGA_VERBOSE) DRM_DEBUG("using iload small\n"); - __mga_iload_small(dev, buf); - } else { - if (MGA_VERBOSE) DRM_DEBUG("using iload xy\n"); - __mga_iload_xy(dev, buf); - } -} -#endif - -static void mga_dma_dispatch_tex_blit(drm_device_t *dev, drm_buf_t *buf ) -{ - int use_agp = PDEA_pagpxfer_enable; - 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; - int x1 = buf_priv->boxes[0].x1; - int y2 = buf_priv->boxes[0].y2; - int x2 = buf_priv->boxes[0].x2; - int dstorg = buf_priv->ContextState[MGA_CTXREG_DSTORG]; - int maccess = buf_priv->ContextState[MGA_CTXREG_MACCESS]; - int pitch = buf_priv->ServerState[MGA_2DREG_PITCH]; - int width, height; - int texperdword = 0; - PRIMLOCALS; - - switch((maccess & 0x00000003)) { - case 0: - texperdword = 4; - break; - case 1: - texperdword = 2; - break; - case 2: - texperdword = 1; - break; - } - - x2 = (x2 + (texperdword - 1)) & ~(texperdword - 1); - x1 = (x1 + (texperdword - 1)) & ~(texperdword - 1); - width = x2 - x1; - height = y2 - y1; - - PRIMRESET(dev_priv); - PRIMGETPTR(dev_priv); - PRIMOUTREG(MGAREG_DSTORG, dstorg); - PRIMOUTREG(MGAREG_MACCESS, maccess); - PRIMOUTREG(MGAREG_PITCH, pitch); - PRIMOUTREG(MGAREG_YDSTLEN, (y1 << 16) | height); - - PRIMOUTREG(MGAREG_FXBNDRY, ((x1+width-1) << 16) | x1); - PRIMOUTREG(MGAREG_AR0, width * height - 1); - PRIMOUTREG(MGAREG_AR3, 0 ); - PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, MGA_ILOAD_CMD); - - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_SRCORG, ((__u32)address) | TT_BLIT); - PRIMOUTREG(MGAREG_SECEND, ((__u32)(address + length)) | use_agp); - - PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); - PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess); - PRIMOUTREG(MGAREG_PITCH, dev_priv->stride); - PRIMOUTREG(MGAREG_AR0, 0 ); - - PRIMOUTREG(MGAREG_AR3, 0 ); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); - - if(sarea_priv->dirty & MGA_DMA_FLUSH) { - DRM_DEBUG("Dma top flush\n"); - while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) ; - sarea_priv->dirty &= ~(MGA_DMA_FLUSH); - } - - - mga_flush_write_combine(); - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); - -} - -static void mga_dma_dispatch_vertex(drm_device_t *dev, drm_buf_t *buf) -{ - - 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; - - drm_buf_t *real_buf = dev->dma->buflist[ buf_priv->vertex_real_idx ]; - unsigned long address = (unsigned long)real_buf->bus_address; - int length = buf->used; - int use_agp = PDEA_pagpxfer_enable; - int i = 0; - PRIMLOCALS; - - PRIMRESET(dev_priv); - - DRM_DEBUG("dispatch vertex %d addr 0x%lx, length 0x%x nbox %d\n", - buf->idx, address, length, buf_priv->nbox); - - if (!buf_priv->vertex_discard) { - - mgaEmitState( dev_priv, buf_priv ); - - do { - if (i < buf_priv->nbox) { - if (0) - DRM_DEBUG("idx %d Emit box %d/%d:" - "%d,%d - %d,%d\n", - buf->idx, - i, buf_priv->nbox, - buf_priv->boxes[i].x1, - buf_priv->boxes[i].y1, - buf_priv->boxes[i].x2, - buf_priv->boxes[i].y2); - - - mgaEmitClipRect( dev_priv, - &buf_priv->boxes[i] ); - } - - PRIMGETPTR(dev_priv); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_SECADDRESS, - ((__u32)address) | TT_VERTEX); - PRIMOUTREG( MGAREG_SECEND, - (((__u32)(address + length)) | - use_agp)); - PRIMADVANCE( dev_priv ); - } while (++i < buf_priv->nbox); - } - - - dev_priv->last_sync_tag = mga_create_sync_tag(dev_priv); - - PRIMGETPTR( dev_priv ); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, dev_priv->last_sync_tag); - PRIMOUTREG(MGAREG_SOFTRAP, 0); - - if(sarea_priv->dirty & MGA_DMA_FLUSH) { - DRM_DEBUG("Dma top flush\n"); - while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) ; - sarea_priv->dirty &= ~(MGA_DMA_FLUSH); - } - - PRIMADVANCE( dev_priv ); - mga_flush_write_combine(); - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); -} - - -/* Not currently used - */ -static void mga_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf) -{ - drm_mga_private_t *dev_priv = dev->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 use_agp = PDEA_pagpxfer_enable; - PRIMLOCALS; - - PRIMRESET(dev_priv); - PRIMGETPTR(dev_priv); - - dev_priv->last_sync_tag = mga_create_sync_tag(dev_priv); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_SECADDRESS, ((__u32)address) | TT_GENERAL); - PRIMOUTREG( MGAREG_SECEND, (((__u32)(address + length)) | use_agp)); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); - PRIMOUTREG( MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); - - if(sarea_priv->dirty & MGA_DMA_FLUSH) { - DRM_DEBUG("Dma top flush\n"); - while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) ; - sarea_priv->dirty &= ~(MGA_DMA_FLUSH); - } - - mga_flush_write_combine(); - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); -} - void mga_wait_usec(int waittime) { struct timeval timep; @@ -792,196 +638,6 @@ void mga_reset_abort(drm_device_t *dev) } } -static void mga_dma_dispatch_clear( drm_device_t *dev, drm_buf_t *buf ) -{ - 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; - int nbox = buf_priv->nbox; - xf86drmClipRectRec *pbox = buf_priv->boxes; - int flags = buf_priv->clear_flags; - unsigned int cmd; - int use_agp = PDEA_pagpxfer_enable; - int i; - PRIMLOCALS; - - if ( dev_priv->sgram ) - cmd = MGA_CLEAR_CMD | DC_atype_blk; - else - cmd = MGA_CLEAR_CMD | DC_atype_rstr; - - - PRIMRESET( dev_priv ); - PRIMGETPTR( dev_priv ); - - for (i = 0 ; i < nbox ; i++) { - unsigned int height = pbox[i].y2 - pbox[i].y1; - - if (MGA_VERBOSE) - DRM_DEBUG("dispatch clear %d,%d-%d,%d flags %x!\n", - pbox[i].x1, - pbox[i].y1, - pbox[i].x2, - pbox[i].y2, - flags); - - - if ( flags & MGA_CLEAR_FRONT ) - { - if (MGA_VERBOSE) - DRM_DEBUG("clear front\n"); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); - PRIMOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_FCOL, buf_priv->clear_color); - PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); - PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); - } - - if ( flags & MGA_CLEAR_BACK ) { - if (MGA_VERBOSE) DRM_DEBUG("clear back\n"); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); - PRIMOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_FCOL, buf_priv->clear_color); - PRIMOUTREG(MGAREG_DSTORG, dev_priv->backOffset); - PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); - } - - if ( flags & MGA_CLEAR_DEPTH ) - { - if (MGA_VERBOSE) DRM_DEBUG("clear depth\n"); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); - PRIMOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_FCOL, buf_priv->clear_zval); - PRIMOUTREG(MGAREG_DSTORG, dev_priv->depthOffset); - PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); - } - } - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); - - if(sarea_priv->dirty & MGA_DMA_FLUSH) { - DRM_DEBUG("Dma top flush\n"); - while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) ; - sarea_priv->dirty &= ~(MGA_DMA_FLUSH); - } - - mga_flush_write_combine(); - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); -} - -static void mga_dma_dispatch_swap( drm_device_t *dev, drm_buf_t *buf ) -{ - 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; - int nbox = buf_priv->nbox; - xf86drmClipRectRec *pbox = buf_priv->boxes; - int use_agp = PDEA_pagpxfer_enable; - int i; - - PRIMLOCALS; - PRIMRESET( dev_priv ); - PRIMGETPTR( dev_priv ); - - PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); - PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess); - PRIMOUTREG(MGAREG_SRCORG, dev_priv->backOffset); - PRIMOUTREG(MGAREG_AR5, dev_priv->stride/2); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD); - - for (i = 0 ; i < nbox; i++) { - unsigned int h = pbox[i].y2 - pbox[i].y1; - unsigned int start = pbox[i].y1 * dev_priv->stride/2; - - if (MGA_VERBOSE) - DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n", - pbox[i].x1, - pbox[i].y1, - pbox[i].x2, - pbox[i].y2); - - PRIMOUTREG(MGAREG_AR0, start + pbox[i].x2 - 1); - PRIMOUTREG(MGAREG_AR3, start + pbox[i].x1); - PRIMOUTREG(MGAREG_FXBNDRY, pbox[i].x1|((pbox[i].x2 - 1)<<16)); - PRIMOUTREG(MGAREG_YDSTLEN+MGAREG_MGA_EXEC, (pbox[i].y1<<16)|h); - } - - PRIMOUTREG( MGAREG_SRCORG, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); - - if(sarea_priv->dirty & MGA_DMA_FLUSH) { - DRM_DEBUG("Dma top flush\n"); - while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) ; - sarea_priv->dirty &= ~(MGA_DMA_FLUSH); - } - - mga_flush_write_combine(); - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); -} - -#if 0 -void mga_force_reset(drm_device_t *dev) -{ - DRM_DEBUG("mga_force_reset\n"); - MGA_WRITE(0x1e40, 0x00000001); - mga_wait_usec(10); - MGA_WRITE(0x1e40, 0x00000000); -} -#endif - -static void mga_dma_dispatch_bad( drm_device_t *dev, drm_buf_t *buf ) -{ - drm_mga_private_t *dev_priv = dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - int use_agp = PDEA_pagpxfer_enable; - - PRIMLOCALS; - PRIMRESET( dev_priv ); - PRIMGETPTR( dev_priv ); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_SOFTRAP, 0); - PRIMADVANCE(dev_priv); - - if(sarea_priv->dirty & MGA_DMA_FLUSH) { - DRM_DEBUG("Dma top flush\n"); - while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) ; - sarea_priv->dirty &= ~(MGA_DMA_FLUSH); - } - - mga_flush_write_combine(); - MGA_WRITE(MGAREG_PRIMADDRESS, dev_priv->prim_phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); -} - /* Frees dispatch lock */ static inline void mga_dma_quiescent(drm_device_t *dev) { @@ -989,13 +645,10 @@ static inline void mga_dma_quiescent(drm_device_t *dev) drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; __volatile__ unsigned int *status = (__volatile__ unsigned int *)dev_priv->status_page; - + while(1) { - atomic_inc(&dev_priv->dispatch_lock); - if(atomic_read(&dev_priv->dispatch_lock) == 1) { - break; - } else { - atomic_dec(&dev_priv->dispatch_lock); + if(!test_and_set_bit(0, &dev_priv->dispatch_lock)) { + break; } } @@ -1005,298 +658,7 @@ static inline void mga_dma_quiescent(drm_device_t *dev) DRM_DEBUG("status[1] : %x last_sync_tag : %x\n", status[1], dev_priv->last_sync_tag); sarea_priv->dirty |= MGA_DMA_FLUSH; - atomic_dec(&dev_priv->dispatch_lock); -} - -/* Keeps dispatch lock held */ - -static inline int mga_dma_is_ready(drm_device_t *dev) -{ - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - - mga_reset_abort(dev); - - atomic_inc(&dev_priv->dispatch_lock); - if(atomic_read(&dev_priv->dispatch_lock) == 1) { - /* We got the lock */ - while((MGA_READ(MGAREG_STATUS) & 0x00020000) != 0x00020000) ; - return 1; - } else { - atomic_dec(&dev_priv->dispatch_lock); - return 0; - } -} - -static inline int mga_dma_is_ready_no_hold(drm_device_t *dev) -{ - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - - atomic_inc(&dev_priv->dispatch_lock); - if(atomic_read(&dev_priv->dispatch_lock) == 1) { - /* We got the lock, but free it */ - atomic_dec(&dev_priv->dispatch_lock); - return 1; - } else { - atomic_dec(&dev_priv->dispatch_lock); - return 0; - } -} - -static void mga_dma_service(int irq, void *device, struct pt_regs *regs) -{ - drm_device_t *dev = (drm_device_t *)device; - drm_device_dma_t *dma = dev->dma; - - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - - atomic_inc(&dev->total_irq); - MGA_WRITE(MGAREG_ICLEAR, 0x00000001); - atomic_dec(&dev_priv->dispatch_lock); - - /* Free previous buffer */ - if (test_and_set_bit(0, &dev->dma_flag)) { - atomic_inc(&dma->total_missed_free); - return; - } - if (dma->this_buffer) { - drm_free_buffer(dev, dma->this_buffer); - dma->this_buffer = NULL; - } - clear_bit(0, &dev->dma_flag); - - /* Dispatch new buffer */ - queue_task(&dev->tq, &tq_immediate); - mark_bh(IMMEDIATE_BH); - -} - -/* Only called by mga_dma_schedule. */ -static int mga_do_dma(drm_device_t *dev, int locked) -{ - drm_buf_t *buf; - int retcode = 0; - drm_device_dma_t *dma = dev->dma; - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_buf_priv_t *buf_priv; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - - if (MGA_VERBOSE) DRM_DEBUG("mga_do_dma\n"); - if (test_and_set_bit(0, &dev->dma_flag)) { - if (MGA_VERBOSE) - DRM_DEBUG("mga_do_dma - busy\n"); - atomic_inc(&dma->total_missed_dma); - return -EBUSY; - } - - if (!dma->next_buffer) { - if (MGA_VERBOSE) - DRM_DEBUG("mga_do_dma - no next buffer\n"); - DRM_ERROR("No next_buffer\n"); - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } - - buf = dma->next_buffer; - - if (MGA_VERBOSE) - DRM_DEBUG("context %d, buffer %d\n", buf->context, buf->idx); - - if (buf->list == DRM_LIST_RECLAIM) { - if (MGA_VERBOSE) - DRM_DEBUG("mga_do_dma - reclaim\n"); - - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - atomic_dec(&dev_priv->pending_bufs); - if(!(atomic_read(&dev_priv->pending_bufs))) { - wake_up_interruptible(&dev->queuelist[DRM_KERNEL_CONTEXT]->flush_queue); - } - clear_bit(0, &dev->dma_flag); - return -EINVAL; - } - - if (!buf->used) { - DRM_ERROR("0 length buffer\n"); - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - clear_bit(0, &dev->dma_flag); - return 0; - } - - if (mga_dma_is_ready(dev) == 0) { - DRM_DEBUG("mga_do_dma - not ready\n"); - clear_bit(0, &dev->dma_flag); - return -EBUSY; - } - - /* Always hold the hardware lock while dispatching. - */ - if ( !locked && - !atomic_read(&dev_priv->in_flush) && - !drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) - { - if (MGA_VERBOSE) - DRM_DEBUG("mga_do_dma - didn't get lock\n"); - atomic_inc(&dma->total_missed_lock); - clear_bit(0, &dev->dma_flag); - atomic_dec(&dev_priv->dispatch_lock); - DRM_DEBUG("NOT LOCKED\n"); - return -EBUSY; - } - - dma->next_queue = dev->queuelist[DRM_KERNEL_CONTEXT]; - drm_clear_next_buffer(dev); - buf->pending = 1; - buf->waiting = 0; - buf->list = DRM_LIST_PEND; - - buf_priv = buf->dev_private; - sarea_priv->last_dispatch = buf_priv->age; - - if (MGA_VERBOSE) - DRM_DEBUG("mga_do_dma - type %d age %d\n", - buf_priv->dma_type, - buf_priv->age); - - - switch (buf_priv->dma_type) { - case MGA_DMA_GENERAL: - mga_dma_dispatch_general(dev, buf); - break; - case MGA_DMA_VERTEX: - mga_dma_dispatch_vertex(dev, buf); - break; -/* case MGA_DMA_SETUP: */ -/* mga_dma_dispatch_setup(dev, address, length); */ -/* break; */ - case MGA_DMA_ILOAD: - mga_dma_dispatch_tex_blit(dev, buf); - break; - case MGA_DMA_SWAP: - mga_dma_dispatch_swap(dev, buf); - break; - case MGA_DMA_CLEAR: - mga_dma_dispatch_clear(dev, buf); - break; - case MGA_DMA_DISCARD: - mga_dma_dispatch_bad(dev, buf); - break; - default: - DRM_DEBUG("bad buffer type %x in dispatch\n", buf_priv->dma_type); - break; - } - - atomic_dec(&dev_priv->pending_bufs); - - if(dma->this_buffer) { - if (MGA_VERBOSE) DRM_DEBUG("mga_do_dma - freeing this_buffer\n"); - drm_free_buffer(dev, dma->this_buffer); - } - - dma->this_buffer = buf; - - atomic_add(buf->used, &dma->total_bytes); - atomic_inc(&dma->total_dmas); - if (!locked && - !atomic_read(&dev_priv->in_flush)) { - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } - } - - clear_bit(0, &dev->dma_flag); - - if(!(atomic_read(&dev_priv->pending_bufs))) { - wake_up_interruptible(&dev->queuelist[DRM_KERNEL_CONTEXT]->flush_queue); - } - - /* We hold the dispatch lock until the interrupt handler - * frees it - */ - return retcode; -} - -static void mga_dma_schedule_tq_wrapper(void *dev) -{ - mga_dma_schedule(dev, 0); -} - -int mga_dma_schedule(drm_device_t *dev, int locked) -{ - drm_queue_t *q; - drm_buf_t *buf; - int retcode = 0; - int processed = 0; - int missed; - int expire = 20; - drm_device_dma_t *dma = dev->dma; - drm_mga_private_t *dev_priv = dev->dev_private; - - - if (MGA_VERBOSE) - DRM_DEBUG("mga_dma_schedule\n"); - - if (test_and_set_bit(0, &dev->interrupt_flag)) { - /* Not reentrant */ - atomic_inc(&dma->total_missed_sched); - return -EBUSY; - } - missed = atomic_read(&dma->total_missed_sched); - -again: - /* There is only one queue: - */ - if (!dma->next_buffer && DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) { - q = dev->queuelist[DRM_KERNEL_CONTEXT]; - buf = drm_waitlist_get(&q->waitlist); - dma->next_buffer = buf; - dma->next_queue = q; - if (buf && buf->list == DRM_LIST_RECLAIM) { - if (MGA_VERBOSE) - DRM_DEBUG("reclaiming in mga_dma_schedule\n"); - drm_clear_next_buffer(dev); - drm_free_buffer(dev, buf); - atomic_dec(&dev_priv->pending_bufs); - if (MGA_VERBOSE) - DRM_DEBUG("pending bufs : %d\n", atomic_read(&dev_priv->pending_bufs)); - if(!(atomic_read(&dev_priv->pending_bufs))) { - wake_up_interruptible(&dev->queuelist[DRM_KERNEL_CONTEXT]->flush_queue); - } - dma->next_buffer = NULL; - goto again; - } - } - - if (dma->next_buffer) { - if (!(retcode = mga_do_dma(dev, locked))) - ++processed; - } - if(!(atomic_read(&dev_priv->pending_bufs))) { - wake_up_interruptible(&dev->queuelist[DRM_KERNEL_CONTEXT]->flush_queue); - } - - - /* Try again if we succesfully dispatched a buffer, or if someone - * tried to schedule while we were working. - */ - if (--expire) { - if (missed != atomic_read(&dma->total_missed_sched)) { - atomic_inc(&dma->total_lost); - if (mga_dma_is_ready_no_hold(dev)) - goto again; - } - - if (processed && mga_dma_is_ready_no_hold(dev)) { - atomic_inc(&dma->total_lost); - processed = 0; - goto again; - } - } - - clear_bit(0, &dev->interrupt_flag); - - return retcode; + clear_bit(0, &dev_priv->dispatch_lock); } int mga_irq_install(drm_device_t *dev, int irq) @@ -1323,15 +685,11 @@ int mga_irq_install(drm_device_t *dev, int irq) dev->dma->this_buffer = NULL; dev->tq.next = NULL; dev->tq.sync = 0; - dev->tq.routine = mga_dma_schedule_tq_wrapper; + dev->tq.routine = mga_dma_task_queue; dev->tq.data = dev; /* Before installing handler */ -#if 0 - MGA_WRITE(MGAREG_ICLEAR, 0x00000001); -#endif MGA_WRITE(MGAREG_IEN, 0); - /* Install handler */ if ((retcode = request_irq(dev->irq, mga_dma_service, @@ -1343,11 +701,9 @@ int mga_irq_install(drm_device_t *dev, int irq) up(&dev->struct_sem); return retcode; } - /* After installing handler */ MGA_WRITE(MGAREG_ICLEAR, 0x00000001); MGA_WRITE(MGAREG_IEN, 0x00000001); - return 0; } @@ -1361,17 +717,10 @@ int mga_irq_uninstall(drm_device_t *dev) up(&dev->struct_sem); if (!irq) return -EINVAL; - - if (MGA_VERBOSE) - DRM_DEBUG("remove irq handler %d\n", irq); - + DRM_DEBUG("remove irq handler %d\n", irq); MGA_WRITE(MGAREG_ICLEAR, 0x00000001); MGA_WRITE(MGAREG_IEN, 0); -#if 0 - MGA_WRITE(MGAREG_ICLEAR, 0x00000001); -#endif free_irq(irq, dev); - return 0; } @@ -1394,46 +743,58 @@ int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, } } -int mga_flush_queue(drm_device_t *dev) +static 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; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; int ret = 0; - - if (MGA_VERBOSE) { - DRM_DEBUG("mga_flush_queue\n"); - DRM_DEBUG("pending_bufs : %d\n", - atomic_read(&dev_priv->pending_bufs)); - } - if(atomic_read(&dev_priv->pending_bufs) != 0) { - if (MGA_VERBOSE) - DRM_DEBUG("got to flush\n"); - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&q->flush_queue, &entry); - for (;;) { - if (!atomic_read(&dev_priv->pending_bufs)) break; - if (MGA_VERBOSE) - DRM_DEBUG("Calling schedule from flush_queue : %d\n", - atomic_read(&dev_priv->pending_bufs)); + if(dev_priv == NULL) { + return 0; + } + + if(dev_priv->next_prim->num_dwords != 0) { + atomic_set(&dev_priv->in_flush, 1); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->flush_queue, &entry); + for (;;) { + if (atomic_read(&dev_priv->in_flush) == 0) break; mga_dma_schedule(dev, 0); - schedule_timeout((HZ/60)); - atomic_inc(&dev->total_sleeps); - if (signal_pending(current)) { - ret = -EINTR; /* Can't restart */ - break; + schedule_timeout(HZ/60); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + break; } } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + } + return ret; +} - if (MGA_VERBOSE) - DRM_DEBUG("Exited out of schedule from flush_queue\n"); +/* Must be called with the lock held */ +void mga_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + drm_device_dma_t *dma = dev->dma; + int i; - current->state = TASK_RUNNING; - remove_wait_queue(&q->flush_queue, &entry); + if (!dma) return; + if(dev->dev_private == NULL) return; + + mga_flush_queue(dev); + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + + if (buf->pid == pid) { + if(buf_priv == NULL) return; + /* Only buffers that need to get reclaimed ever + * get set to free */ + if(buf_priv->age == MGA_BUF_USED) + buf_priv->age = MGA_BUF_FREE; + } } - - return ret; } int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, @@ -1442,7 +803,6 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - DECLARE_WAITQUEUE(entry, current); int ret = 0; drm_lock_t lock; @@ -1459,7 +819,6 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, lock.context, current->pid, dev->lock.hw_lock->lock, lock.flags); - if (lock.context < 0) { return -EINVAL; } @@ -1486,7 +845,6 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; - current->policy |= SCHED_YIELD; DRM_DEBUG("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { @@ -1501,10 +859,8 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, if (!ret) { if (lock.flags & _DRM_LOCK_QUIESCENT) { DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); - atomic_set(&dev_priv->in_flush, 1); mga_flush_queue(dev); mga_dma_quiescent(dev); - atomic_set(&dev_priv->in_flush, 0); } } @@ -1520,11 +876,6 @@ int mga_flush_ioctl(struct inode *inode, struct file *filp, drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; DRM_DEBUG("mga_flush_ioctl\n"); - atomic_set(&dev_priv->in_flush, 1); mga_flush_queue(dev); -#if 0 - mga_dma_quiescent(dev); -#endif - atomic_set(&dev_priv->in_flush, 0); return 0; } diff --git a/linux/mga_dma.h b/linux/mga_dma.h index e91f608b..99fdf4a5 100644 --- a/linux/mga_dma.h +++ b/linux/mga_dma.h @@ -2,35 +2,17 @@ #define MGA_DMA_H #include "mga_drm_public.h" +typedef enum { + TT_GENERAL, + TT_BLIT, + TT_VECTOR, + TT_VERTEX +} transferType_t; - -/* Isn't this fun - we copy the outstanding card state for every - * MGA_DMA_VERTEX buffer. This has to be fixed asap by emitting - * primary dma commands in the 'vertex_dma' ioctl. - */ typedef struct { - int dma_type; - - unsigned int ContextState[MGA_CTX_SETUP_SIZE]; - unsigned int ServerState[MGA_2D_SETUP_SIZE]; - unsigned int TexState[2][MGA_TEX_SETUP_SIZE]; - unsigned int WarpPipe; - unsigned int dirty; - - unsigned short clear_color; - unsigned short clear_zval; - unsigned int clear_flags; - - unsigned int vertex_real_idx; - unsigned int vertex_discard; - unsigned int age; - - unsigned int nbox; - xf86drmClipRectRec boxes[MGA_NR_SAREA_CLIPRECTS]; } drm_mga_buf_priv_t; - #define MGA_DMA_GENERAL 0 /* not used */ #define MGA_DMA_VERTEX 1 #define MGA_DMA_SETUP 2 @@ -39,7 +21,6 @@ typedef struct { #define MGA_DMA_SWAP 5 /* placeholder */ #define MGA_DMA_DISCARD 6 - #define DWGREG0 0x1c00 #define DWGREG0_END 0x1dff #define DWGREG1 0x2c00 @@ -50,93 +31,72 @@ typedef struct { #define ADRINDEX1(r) (u8)(((r - DWGREG1) >> 2) | 0x80) #define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r)) - - #define MGA_VERBOSE 0 +#define MGA_NUM_PRIM_BUFS 4 +/* Primary buffer versions of above -- pretty similar really. + */ +#define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \ + int outcount, num_dwords -/* Macros for inserting commands into a secondary dma buffer. - */ -#define DMALOCALS u8 tempIndex[4]; u32 *dma_ptr; \ - int outcount, num_dwords; - -#define DMAGETPTR(buf) do { \ - dma_ptr = (u32 *)((u8 *)buf->address + buf->used); \ - outcount = 0; \ - num_dwords = buf->used / 4; \ - if (MGA_VERBOSE) \ - printk(KERN_INFO "DMAGETPTR in %s, start %d\n", \ - __FUNCTION__, num_dwords); \ +#define PRIM_OVERFLOW(dev, dev_priv, length) do { \ +drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ +if( (tmp_buf->max_dwords - tmp_buf->num_dwords) < length || \ + tmp_buf->sec_used > (MGA_DMA_BUF_NR / 2)) { \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ + } \ } while(0) -#define DMAADVANCE(buf) do { \ - if (MGA_VERBOSE) \ - printk(KERN_INFO "DMAADVANCE\n"); \ - buf->used = num_dwords * 4; \ +#define PRIMGETPTR(dev_priv) do { \ +drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ +if(MGA_VERBOSE) \ +printk("PRIMGETPTR in %s\n", __FUNCTION__); \ +dma_ptr = tmp_buf->current_dma_ptr; \ +num_dwords = tmp_buf->num_dwords; \ +phys_head = tmp_buf->phys_head; \ +outcount = 0; \ } while(0) -#define DMAOUTREG(reg, val) do { \ - tempIndex[outcount]=ADRINDEX(reg); \ - dma_ptr[++outcount] = val; \ - if (MGA_VERBOSE) \ - printk(KERN_INFO \ - " DMAOUT %d: 0x%x -- 0x%x\n", \ - num_dwords +1+outcount, ADRINDEX(reg), val); \ - if (outcount == 4) { \ - outcount = 0; \ - dma_ptr[0] = *(u32 *)tempIndex; \ - dma_ptr+=5; \ - num_dwords += 5; \ - } \ -}while (0) - - - -/* Primary buffer versions of above -- pretty similar really. - */ -#define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \ - int outcount, num_dwords - -#define PRIMRESET(dev_priv) do { \ - dev_priv->prim_num_dwords = 0; \ - dev_priv->current_dma_ptr = dev_priv->prim_head; \ -} while (0) - -#define PRIMGETPTR(dev_priv) do { \ - dma_ptr = dev_priv->current_dma_ptr; \ - phys_head = dev_priv->prim_phys_head; \ - num_dwords = dev_priv->prim_num_dwords; \ - outcount = 0; \ - if (MGA_VERBOSE) \ - printk(KERN_INFO "PRIMGETPTR in %s, start %d\n", \ - __FUNCTION__, num_dwords); \ -} while (0) +#define PRIMPTR(prim_buf) do { \ +if(MGA_VERBOSE) \ +printk("PRIMPTR in %s\n", __FUNCTION__); \ +dma_ptr = prim_buf->current_dma_ptr; \ +num_dwords = prim_buf->num_dwords; \ +phys_head = prim_buf->phys_head; \ +outcount = 0; \ +} while(0) -#define PRIMADVANCEPAD(dev_priv) do { \ - while(outcount & 3) { \ - if (MGA_VERBOSE) \ - printk(KERN_INFO "PAD %d\n", \ - num_dwords + 1 + outcount); \ - tempIndex[outcount++]=0x15; \ - } \ - \ - if (MGA_VERBOSE) \ - printk(KERN_INFO "PRIMADVANCEPAD\n"); \ - dev_priv->prim_num_dwords = num_dwords; \ - dev_priv->current_dma_ptr = dma_ptr; \ -} while (0) +#define PRIMFINISH(prim_buf) do { \ + if (MGA_VERBOSE) { \ + printk(KERN_INFO "PRIMFINISH in %s\n", __FUNCTION__); \ + if (outcount & 3) \ + printk(KERN_INFO " --- truncation\n"); \ + } \ + prim_buf->num_dwords = num_dwords; \ + prim_buf->current_dma_ptr = dma_ptr; \ +} while(0) #define PRIMADVANCE(dev_priv) do { \ +drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ if (MGA_VERBOSE) { \ - printk(KERN_INFO "PRIMADVANCE\n"); \ + printk(KERN_INFO "PRIMADVANCE in %s\n", __FUNCTION__); \ if (outcount & 3) \ printk(KERN_INFO " --- truncation\n"); \ } \ - dev_priv->prim_num_dwords = num_dwords; \ - dev_priv->current_dma_ptr = dma_ptr; \ + tmp_buf->num_dwords = num_dwords; \ + tmp_buf->current_dma_ptr = dma_ptr; \ } while (0) +#define PRIMUPDATE(dev_priv) do { \ +drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + tmp_buf->sec_used++; \ +} while (0) #define PRIMOUTREG(reg, val) do { \ tempIndex[outcount]=ADRINDEX(reg); \ @@ -153,9 +113,6 @@ typedef struct { } \ }while (0) - - - #define MGA_CLEAR_CMD (DC_opcod_trap | DC_arzero_enable | \ DC_sgnzero_enable | DC_shftzero_enable | \ (0xC << DC_bop_SHIFT) | DC_clipdis_enable | \ diff --git a/linux/mga_drm_public.h b/linux/mga_drm_public.h index 7a69afc2..1c0a4a9e 100644 --- a/linux/mga_drm_public.h +++ b/linux/mga_drm_public.h @@ -204,10 +204,6 @@ typedef struct int ctxOwner; mgaTexRegion texList[MGA_NR_TEX_REGIONS+1]; int texAge; - - - - } drm_mga_sarea_t; diff --git a/linux/mga_drv.h b/linux/mga_drv.h index c4eb6cf3..fbc07b5a 100644 --- a/linux/mga_drv.h +++ b/linux/mga_drv.h @@ -33,6 +33,18 @@ #define _MGA_DRV_H_ #include "mga_drm_public.h" +typedef struct { + unsigned int num_dwords; + unsigned int max_dwords; + u32 *current_dma_ptr; + u32 *head; + u32 phys_head; + int sec_used; + int idx; + u32 in_use; + atomic_t force_fire; +} drm_mga_prim_buf_t; + typedef struct _drm_mga_private { int reserved_map_idx; int buffer_map_idx; @@ -52,26 +64,26 @@ typedef struct _drm_mga_private { mgaWarpIndex WarpIndex[MGA_MAX_G400_PIPES]; unsigned int WarpPipe; __volatile__ unsigned long softrap_age; - atomic_t dispatch_lock; - atomic_t pending_bufs; + u32 dispatch_lock; atomic_t in_flush; + atomic_t in_wait; unsigned int last_sync_tag; unsigned int sync_tag; void *status_page; unsigned long real_status_page; - void *ioremap; - u32 *prim_head; - u32 *current_dma_ptr; - u32 prim_phys_head; - int prim_num_dwords; - int prim_max_dwords; + u8 *ioremap; + drm_mga_prim_buf_t **prim_bufs; + drm_mga_prim_buf_t *next_prim; + drm_mga_prim_buf_t *last_prim; + drm_mga_prim_buf_t *current_prim; + int current_prim_idx; struct pci_dev *device; - + wait_queue_head_t flush_queue; /* Processes waiting until flush */ + wait_queue_head_t wait_queue; /* Processes waiting until interrupt */ /* Some validated register values: */ u32 mAccess; - } drm_mga_private_t; /* mga_drv.c */ @@ -97,13 +109,17 @@ extern int mga_control(struct inode *inode, struct file *filp, extern int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +/* mga_dma_init does init and release */ extern int mga_dma_init(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int mga_dma_cleanup(drm_device_t *dev); extern int mga_flush_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -/* mga_dma_init does init and release */ +extern unsigned int mga_create_sync_tag(drm_mga_private_t *dev_priv); +extern drm_buf_t *mga_freelist_get(drm_device_t *dev); +extern int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf); +extern int mga_advance_primary(drm_device_t *dev); /* mga_bufs.c */ diff --git a/linux/mga_state.c b/linux/mga_state.c index ad72a4dd..ef3f7668 100644 --- a/linux/mga_state.c +++ b/linux/mga_state.c @@ -35,13 +35,13 @@ #include "mga_drv.h" #include "mgareg_flags.h" #include "mga_dma.h" -#include "mga_state.h" #include "drm.h" -void mgaEmitClipRect( drm_mga_private_t *dev_priv, xf86drmClipRectRec *box ) +static void mgaEmitClipRect( drm_mga_private_t *dev_priv, xf86drmClipRectRec *box ) { PRIMLOCALS; + /* This takes a max of 10 dwords */ PRIMGETPTR( dev_priv ); /* The G400 seems to have an issue with the second WARP not @@ -52,8 +52,8 @@ void mgaEmitClipRect( drm_mga_private_t *dev_priv, xf86drmClipRectRec *box ) if (dev_priv->chipset == MGA_CARD_TYPE_G400) { PRIMOUTREG( MGAREG_DMAPAD, 0 ); PRIMOUTREG( MGAREG_DMAPAD, 0 ); - PRIMOUTREG( MGAREG_DWGSYNC, 0 ); - PRIMOUTREG( MGAREG_DWGSYNC, 0 ); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag - 1 ); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag - 1 ); } PRIMOUTREG( MGAREG_CXBNDRY, ((box->x2)<<16)|(box->x1) ); @@ -64,13 +64,13 @@ void mgaEmitClipRect( drm_mga_private_t *dev_priv, xf86drmClipRectRec *box ) PRIMADVANCE( dev_priv ); } - -static void mgaEmitContext(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv) +static void mgaEmitContext(drm_mga_private_t *dev_priv ) { - unsigned int *regs = buf_priv->ContextState; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; PRIMLOCALS; + /* This takes a max of 15 dwords */ PRIMGETPTR( dev_priv ); PRIMOUTREG( MGAREG_DSTORG, regs[MGA_CTXREG_DSTORG] ); @@ -81,9 +81,7 @@ static void mgaEmitContext(drm_mga_private_t *dev_priv, PRIMOUTREG( MGAREG_ALPHACTRL, regs[MGA_CTXREG_ALPHACTRL] ); PRIMOUTREG( MGAREG_FOGCOL, regs[MGA_CTXREG_FOGCOLOR] ); PRIMOUTREG( MGAREG_WFLAG, regs[MGA_CTXREG_WFLAG] ); - PRIMOUTREG( MGAREG_ZORG, dev_priv->depthOffset ); /* invarient */ -/* PRIMOUTREG( MGAREG_DMAPAD, 0 ); */ if (dev_priv->chipset == MGA_CARD_TYPE_G400) { PRIMOUTREG( MGAREG_WFLAG1, regs[MGA_CTXREG_WFLAG] ); @@ -92,16 +90,18 @@ static void mgaEmitContext(drm_mga_private_t *dev_priv, PRIMOUTREG( MGAREG_DMAPAD, 0 ); } - PRIMADVANCE( dev_priv ); /* padded */ + PRIMADVANCE( dev_priv ); } -static void mgaG200EmitTex( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG200EmitTex( drm_mga_private_t *dev_priv ) { - unsigned int *regs = buf_priv->TexState[0]; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->TexState[0]; PRIMLOCALS; PRIMGETPTR( dev_priv ); + + /* This takes 20 dwords */ PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); @@ -126,14 +126,16 @@ static void mgaG200EmitTex( drm_mga_private_t *dev_priv, PRIMADVANCE( dev_priv ); } -static void mgaG400EmitTex0( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG400EmitTex0( drm_mga_private_t *dev_priv ) { - unsigned int *regs = buf_priv->TexState[0]; - int multitex = buf_priv->WarpPipe & MGA_T2; - + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->TexState[0]; + int multitex = sarea_priv->WarpPipe & MGA_T2; PRIMLOCALS; + PRIMGETPTR( dev_priv ); + + /* This takes a max of 30 dwords */ PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); @@ -167,21 +169,20 @@ static void mgaG400EmitTex0( drm_mga_private_t *dev_priv, PRIMOUTREG( MGAREG_TEXTRANS, 0xffff ); PRIMOUTREG( MGAREG_TEXTRANSHIGH, 0xffff ); - PRIMADVANCE( dev_priv ); } #define TMC_map1_enable 0x80000000 - -static void mgaG400EmitTex1( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG400EmitTex1( drm_mga_private_t *dev_priv ) { - unsigned int *regs = buf_priv->TexState[1]; - + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->TexState[1]; PRIMLOCALS; + PRIMGETPTR(dev_priv); + /* This takes 25 dwords */ PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | TMC_map1_enable); PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); @@ -207,19 +208,19 @@ static void mgaG400EmitTex1( drm_mga_private_t *dev_priv, PRIMOUTREG( MGAREG_TEXTRANSHIGH, 0xffff ); PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); - PRIMADVANCE( dev_priv ); /* padded */ + PRIMADVANCE( dev_priv ); } - -static void mgaG400EmitPipe(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv) +static void mgaG400EmitPipe(drm_mga_private_t *dev_priv ) { - unsigned int pipe = buf_priv->WarpPipe; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int pipe = sarea_priv->WarpPipe; float fParam = 12800.0f; PRIMLOCALS; PRIMGETPTR(dev_priv); + /* This takes 25 dwords */ /* Establish vertex size. */ @@ -259,13 +260,15 @@ static void mgaG400EmitPipe(drm_mga_private_t *dev_priv, PRIMADVANCE(dev_priv); } -static void mgaG200EmitPipe( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv ) +static void mgaG200EmitPipe( drm_mga_private_t *dev_priv ) { - unsigned int pipe = buf_priv->WarpPipe; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int pipe = sarea_priv->WarpPipe; PRIMLOCALS; PRIMGETPTR(dev_priv); + + /* This takes 15 dwords */ PRIMOUTREG(MGAREG_WIADDR, WIA_wmode_suspend); PRIMOUTREG(MGAREG_WVRTXSZ, 7); @@ -287,60 +290,94 @@ static void mgaG200EmitPipe( drm_mga_private_t *dev_priv, PRIMADVANCE(dev_priv); } -void mgaEmitState( drm_mga_private_t *dev_priv, drm_mga_buf_priv_t *buf_priv ) +static void mgaEmitState( drm_mga_private_t *dev_priv ) { - unsigned int dirty = buf_priv->dirty; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; if (dev_priv->chipset == MGA_CARD_TYPE_G400) { - int multitex = buf_priv->WarpPipe & MGA_T2; + int multitex = sarea_priv->WarpPipe & MGA_T2; -/* printk("BUF PIPE: %x LOADED PIPE: %x\n", */ -/* buf_priv->WarpPipe, dev_priv->WarpPipe); */ +/* DRM_DEBUG("BUF PIPE: %x LOADED PIPE: %x\n", */ +/* sarea_priv->WarpPipe, dev_priv->WarpPipe); */ - if (buf_priv->WarpPipe != dev_priv->WarpPipe) { - mgaG400EmitPipe( dev_priv, buf_priv ); - dev_priv->WarpPipe = buf_priv->WarpPipe; + if (sarea_priv->WarpPipe != dev_priv->WarpPipe) { + mgaG400EmitPipe( dev_priv ); + dev_priv->WarpPipe = sarea_priv->WarpPipe; } if (dirty & MGA_UPLOAD_CTX) - mgaEmitContext( dev_priv, buf_priv ); + mgaEmitContext( dev_priv ); if (dirty & MGA_UPLOAD_TEX0) - mgaG400EmitTex0( dev_priv, buf_priv ); + mgaG400EmitTex0( dev_priv ); if ((dirty & MGA_UPLOAD_TEX1) && multitex) - mgaG400EmitTex1( dev_priv, buf_priv ); + mgaG400EmitTex1( dev_priv ); } else { - if (buf_priv->WarpPipe != dev_priv->WarpPipe) { - mgaG200EmitPipe( dev_priv, buf_priv ); - dev_priv->WarpPipe = buf_priv->WarpPipe; + if (sarea_priv->WarpPipe != dev_priv->WarpPipe) { + mgaG200EmitPipe( dev_priv ); + dev_priv->WarpPipe = sarea_priv->WarpPipe; } if (dirty & MGA_UPLOAD_CTX) - mgaEmitContext( dev_priv, buf_priv ); + mgaEmitContext( dev_priv ); if (dirty & MGA_UPLOAD_TEX0) - mgaG200EmitTex( dev_priv, buf_priv ); - } + mgaG200EmitTex( dev_priv ); + } + + sarea_priv->dirty = 0; } +/* WARNING if you change any of the state functions + * verify these numbers */ +static int mgaCalcState( drm_mga_private_t *dev_priv ) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + int size = 0; + + if (dev_priv->chipset == MGA_CARD_TYPE_G400) { + int multitex = sarea_priv->WarpPipe & MGA_T2; + + if (sarea_priv->WarpPipe != dev_priv->WarpPipe) { + size += 25; + } + if (dirty & MGA_UPLOAD_CTX) { + size += 15; + } + if (dirty & MGA_UPLOAD_TEX0) { + size += 30; + } + if ((dirty & MGA_UPLOAD_TEX1) && multitex) { + size += 25; + } + } else { + if (sarea_priv->WarpPipe != dev_priv->WarpPipe) { + size += 15; + } + if (dirty & MGA_UPLOAD_CTX) { + size += 15; + } + if (dirty & MGA_UPLOAD_TEX0) { + size += 20; + } + } + return size; +} /* Disallow all write destinations except the front and backbuffer. */ -static int mgaCopyContext(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv) +static int mgaVerifyContext(drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - unsigned int *regs = buf_priv->ContextState; - - memcpy(regs, - sarea_priv->ContextState, - sizeof(buf_priv->ContextState)); + unsigned int *regs = sarea_priv->ContextState; if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOffset && regs[MGA_CTXREG_DSTORG] != dev_priv->backOffset) { - printk("BAD DSTORG: %x (front %x, back %x)\n\n", + DRM_DEBUG("BAD DSTORG: %x (front %x, back %x)\n\n", regs[MGA_CTXREG_DSTORG], dev_priv->frontOffset, dev_priv->backOffset); regs[MGA_CTXREG_DSTORG] = 0; @@ -350,79 +387,531 @@ static int mgaCopyContext(drm_mga_private_t *dev_priv, return 0; } - /* Disallow texture reads from PCI space. */ -static int mgaCopyTex(drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv, +static int mgaVerifyTex(drm_mga_private_t *dev_priv, int unit) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - memcpy(buf_priv->TexState[unit], sarea_priv->TexState[unit], - sizeof(buf_priv->TexState[0])); - - if ((buf_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) { - printk("BAD TEXREG_ORG: %x, unit %d\n", + if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) { + DRM_DEBUG("BAD TEXREG_ORG: %x, unit %d\n", sarea_priv->TexState[unit][MGA_TEXREG_ORG], unit); - buf_priv->TexState[unit][MGA_TEXREG_ORG] = 0; + sarea_priv->TexState[unit][MGA_TEXREG_ORG] = 0; return -1; } return 0; } - -int mgaCopyAndVerifyState( drm_mga_private_t *dev_priv, - drm_mga_buf_priv_t *buf_priv, - unsigned int interested ) +static int mgaVerifyState( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - unsigned int dirty = interested & sarea_priv->dirty; + unsigned int dirty = sarea_priv->dirty; int rv = 0; - buf_priv->dirty = dirty; - sarea_priv->dirty &= ~interested; - - buf_priv->WarpPipe = sarea_priv->WarpPipe; - -/* if (interested & MGA_UPLOAD_CLIPRECTS) */ - { - buf_priv->nbox = sarea_priv->nbox; - - if (buf_priv->nbox >= MGA_NR_SAREA_CLIPRECTS) - buf_priv->nbox = MGA_NR_SAREA_CLIPRECTS; - - if (buf_priv->nbox) - memcpy( buf_priv->boxes, - sarea_priv->boxes, - buf_priv->nbox * sizeof(xf86drmClipRectRec)); - } + if (sarea_priv->nbox >= MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; if (dirty & MGA_UPLOAD_CTX) - rv |= mgaCopyContext( dev_priv, buf_priv ); + rv |= mgaVerifyContext( dev_priv ); if (dirty & MGA_UPLOAD_TEX0) - rv |= mgaCopyTex( dev_priv, buf_priv, 0 ); + rv |= mgaVerifyTex( dev_priv, 0 ); if (dev_priv->chipset == MGA_CARD_TYPE_G400) { if (dirty & MGA_UPLOAD_TEX1) - rv |= mgaCopyTex( dev_priv, buf_priv, 1 ); + rv |= mgaVerifyTex( dev_priv, 1 ); if (dirty & MGA_UPLOAD_PIPE) - rv |= (buf_priv->WarpPipe > MGA_MAX_G400_PIPES); + rv |= (sarea_priv->WarpPipe > MGA_MAX_G400_PIPES); } else { if (dirty & MGA_UPLOAD_PIPE) - rv |= (buf_priv->WarpPipe > MGA_MAX_G200_PIPES); + rv |= (sarea_priv->WarpPipe > MGA_MAX_G200_PIPES); } + return rv == 0; +} +#if 0 +/* This is very broken */ - return rv == 0; +static void mga_dma_dispatch_tex_blit(drm_device_t *dev, drm_buf_t *buf, u16 x1, + u16 x2, u16 y1, u16 y2, unsigned int destOrg, + unsigned int mAccess, unsigned int pitch) +{ + int use_agp = PDEA_pagpxfer_enable; + 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; + int width, height; + int texperdword = 0; + PRIMLOCALS; + + switch((maccess & 0x00000003)) { + case 0: + texperdword = 4; + break; + case 1: + texperdword = 2; + break; + case 2: + texperdword = 1; + break; + } + + length = (y2 - y1) * (x2 - x1) / texperdword; + + x2 = (x2 + (texperdword - 1)) & ~(texperdword - 1); + x1 = (x1 + (texperdword - 1)) & ~(texperdword - 1); + width = x2 - x1; + height = y2 - y1; + + PRIMRESET(dev_priv); + PRIMGETPTR(dev_priv); + PRIMOUTREG(MGAREG_DSTORG, dstorg); + PRIMOUTREG(MGAREG_MACCESS, maccess); + PRIMOUTREG(MGAREG_PITCH, pitch); + PRIMOUTREG(MGAREG_YDSTLEN, (y1 << 16) | height); + + PRIMOUTREG(MGAREG_FXBNDRY, ((x1+width-1) << 16) | x1); + PRIMOUTREG(MGAREG_AR0, width * height - 1); + PRIMOUTREG(MGAREG_AR3, 0 ); + PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, MGA_ILOAD_CMD); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_SRCORG, ((__u32)address) | TT_BLIT); + PRIMOUTREG(MGAREG_SECEND, ((__u32)(address + length)) | use_agp); + + PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); + PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess); + PRIMOUTREG(MGAREG_PITCH, dev_priv->stride); + PRIMOUTREG(MGAREG_AR0, 0 ); + + PRIMOUTREG(MGAREG_AR3, 0 ); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_SOFTRAP, 0); + PRIMADVANCE(dev_priv); } +#endif + +static inline void mga_dma_dispatch_vertex(drm_device_t *dev, + drm_buf_t *buf, int real_idx, + int idx) +{ + 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 use_agp = PDEA_pagpxfer_enable; + int i = 0; + PRIMLOCALS; + int primary_needed; + + DRM_DEBUG("dispatch vertex %d addr 0x%lx, length 0x%x nbox %d dirty %x\n", + buf->idx, address, length, sarea_priv->nbox, sarea_priv->dirty); + + primary_needed = mgaCalcState( dev_priv ); + /* Primary needed is in dwords */ + if (sarea_priv->nbox == 0) { + primary_needed += 5; + } else { + primary_needed += (5 * sarea_priv->nbox); + primary_needed += (10 * sarea_priv->nbox); + } + primary_needed += 5; /* For the dwgsync */ + PRIM_OVERFLOW(dev, dev_priv, primary_needed); + dev_priv->last_sync_tag = mga_create_sync_tag(dev_priv); + if(real_idx == idx) { + buf_priv->age = dev_priv->last_sync_tag; + } + mgaEmitState( dev_priv ); + do { + if (i < sarea_priv->nbox) { + DRM_DEBUG("idx %d Emit box %d/%d:" + "%d,%d - %d,%d\n", + buf->idx, + i, sarea_priv->nbox, + sarea_priv->boxes[i].x1, + sarea_priv->boxes[i].y1, + sarea_priv->boxes[i].x2, + sarea_priv->boxes[i].y2); + + mgaEmitClipRect( dev_priv, + &sarea_priv->boxes[i] ); + } + PRIMGETPTR(dev_priv); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_SECADDRESS, + ((__u32)address) | TT_VERTEX); + PRIMOUTREG( MGAREG_SECEND, + (((__u32)(address + length)) | + use_agp)); + PRIMADVANCE( dev_priv ); + } while (++i < sarea_priv->nbox); + + PRIMGETPTR( dev_priv ); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMADVANCE( dev_priv ); +} +/* Not currently used + */ +static inline void mga_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + unsigned long address = (unsigned long)buf->bus_address; + int length = buf->used; + int use_agp = PDEA_pagpxfer_enable; + PRIMLOCALS; + + PRIM_OVERFLOW(dev, dev_priv, 10); + PRIMGETPTR(dev_priv); + + dev_priv->last_sync_tag = mga_create_sync_tag(dev_priv); + buf_priv->age = dev_priv->last_sync_tag; + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_SECADDRESS, ((__u32)address) | TT_GENERAL); + PRIMOUTREG( MGAREG_SECEND, (((__u32)(address + length)) | use_agp)); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMADVANCE(dev_priv); +} + +static inline void mga_dma_dispatch_clear( drm_device_t *dev, int flags, + unsigned int clear_color, + unsigned int clear_zval ) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + int nbox = sarea_priv->nbox; + xf86drmClipRectRec *pbox = sarea_priv->boxes; + unsigned int cmd; + int i; + int primary_needed; + PRIMLOCALS; + + if ( dev_priv->sgram ) + cmd = MGA_CLEAR_CMD | DC_atype_blk; + else + cmd = MGA_CLEAR_CMD | DC_atype_rstr; + + primary_needed = nbox * 35; + if(primary_needed == 0) primary_needed = 35; + PRIM_OVERFLOW(dev, dev_priv, primary_needed); + PRIMGETPTR( dev_priv ); + dev_priv->last_sync_tag = mga_create_sync_tag(dev_priv); + + for (i = 0 ; i < nbox ; i++) { + unsigned int height = pbox[i].y2 - pbox[i].y1; + + DRM_DEBUG("dispatch clear %d,%d-%d,%d flags %x!\n", + pbox[i].x1, pbox[i].y1, pbox[i].x2, + pbox[i].y2, flags); + + if ( flags & MGA_CLEAR_FRONT ) { + DRM_DEBUG("clear front\n"); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); + PRIMOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_FCOL, clear_color); + PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); + PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + + if ( flags & MGA_CLEAR_BACK ) { + DRM_DEBUG("clear back\n"); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); + PRIMOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_FCOL, clear_color); + PRIMOUTREG(MGAREG_DSTORG, dev_priv->backOffset); + PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + + if ( flags & MGA_CLEAR_DEPTH ) { + DRM_DEBUG("clear depth\n"); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); + PRIMOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_FCOL, clear_zval); + PRIMOUTREG(MGAREG_DSTORG, dev_priv->depthOffset); + PRIMOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + } + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMADVANCE(dev_priv); +} + +static inline void mga_dma_dispatch_swap( drm_device_t *dev ) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + int nbox = sarea_priv->nbox; + xf86drmClipRectRec *pbox = sarea_priv->boxes; + int i; + int primary_needed; + PRIMLOCALS; + + primary_needed = nbox * 5; + primary_needed += 15; + PRIM_OVERFLOW(dev, dev_priv, primary_needed); + PRIMGETPTR( dev_priv ); + + dev_priv->last_sync_tag = mga_create_sync_tag(dev_priv); + + PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); + PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess); + PRIMOUTREG(MGAREG_SRCORG, dev_priv->backOffset); + PRIMOUTREG(MGAREG_AR5, dev_priv->stride/2); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD); + + for (i = 0 ; i < nbox; i++) { + unsigned int h = pbox[i].y2 - pbox[i].y1; + unsigned int start = pbox[i].y1 * dev_priv->stride/2; + + DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n", + pbox[i].x1, pbox[i].y1, + pbox[i].x2, pbox[i].y2); + + PRIMOUTREG(MGAREG_AR0, start + pbox[i].x2 - 1); + PRIMOUTREG(MGAREG_AR3, start + pbox[i].x1); + PRIMOUTREG(MGAREG_FXBNDRY, pbox[i].x1|((pbox[i].x2 - 1)<<16)); + PRIMOUTREG(MGAREG_YDSTLEN+MGAREG_MGA_EXEC, (pbox[i].y1<<16)|h); + } + + PRIMOUTREG( MGAREG_SRCORG, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMADVANCE(dev_priv); +} + +int mga_clear_bufs(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_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + + drm_mga_clear_t clear; + + copy_from_user_ret(&clear, (drm_mga_clear_t *)arg, sizeof(clear), + -EFAULT); + + if (sarea_priv->nbox >= MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; + + /* Make sure we restore the 3D state next time. + */ + dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX; + mga_dma_dispatch_clear( dev, clear.flags, + clear.clear_color, + clear.clear_depth ); + PRIMUPDATE(dev_priv); + mga_dma_schedule(dev, 1); + sarea_priv->last_dispatch = status[1]; + return 0; +} + +int mga_swap_bufs(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_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + + if (sarea_priv->nbox >= MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; + + /* Make sure we restore the 3D state next time. + */ + dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX; + mga_dma_dispatch_swap( dev ); + PRIMUPDATE(dev_priv); + atomic_set(&dev_priv->current_prim->force_fire, 1); + mga_dma_schedule(dev, 1); + sarea_priv->last_dispatch = status[1]; + return 0; +} + +/* This is very broken */ +int mga_iload(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_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + drm_mga_iload_t iload; + + copy_from_user_ret(&iload, (drm_mga_iload_t *)arg, sizeof(iload), + -EFAULT); + buf = dma->buflist[iload.idx]; +#if 0 + sarea_priv->dirty |= (MGA_UPLOAD_CTX | MGA_UPLOAD_2D); + + DRM_DEBUG("buf->used : %d\n", buf->used); + + mga_dma_dispatch_tex_blit(dev, buf, iload.x1, iload.x2, iload.y1, iload.y2, + iload.destOrg, iload.mAccess, iload.pitch); + + mga_dma_schedule(dev, 1); +#endif + mga_freelist_put(dev, buf); + sarea_priv->last_dispatch = status[1]; + return 0; +} + +int mga_vertex(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_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_vertex_t vertex; + + copy_from_user_ret(&vertex, (drm_mga_vertex_t *)arg, sizeof(vertex), + -EFAULT); + + buf = dma->buflist[ vertex.real_idx ]; + buf_priv = buf->dev_private; + + if (!mgaVerifyState(dev_priv)) { + if(vertex.real_idx == vertex.idx) + buf_priv->age = dev_priv->last_sync_tag; + return -EINVAL; + } + + buf->used = vertex.real_used; + if(vertex.discard) { + buf_priv->age = dev_priv->last_sync_tag; + } else { + mga_dma_dispatch_vertex(dev, buf, vertex.real_idx, + vertex.idx); + } + PRIMUPDATE(dev_priv); + mga_dma_schedule(dev, 1); + sarea_priv->last_dispatch = status[1]; + return 0; +} + +static int mga_dma_get_buffers(drm_device_t *dev, drm_dma_t *d) +{ + int i; + drm_buf_t *buf; + + for (i = d->granted_count; i < d->request_count; i++) { + buf = mga_freelist_get(dev); + if (!buf) break; + buf->pid = current->pid; + copy_to_user_ret(&d->request_indices[i], + &buf->idx, + sizeof(buf->idx), + -EFAULT); + copy_to_user_ret(&d->request_sizes[i], + &buf->total, + sizeof(buf->total), + -EFAULT); + ++d->granted_count; + } + return 0; +} + +int mga_dma(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_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + __volatile__ unsigned int *status = + (__volatile__ unsigned int *)dev_priv->status_page; + int retcode = 0; + drm_dma_t d; + + copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); + DRM_DEBUG("%d %d: %d send, %d req\n", + current->pid, d.context, d.send_count, d.request_count); + + /* Please don't send us buffers. + */ + if (d.send_count != 0) { + DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", + current->pid, d.send_count); + return -EINVAL; + } + + /* We'll send you buffers. + */ + if (d.request_count < 0 || d.request_count > dma->buf_count) { + DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", + current->pid, d.request_count, dma->buf_count); + return -EINVAL; + } + + d.granted_count = 0; + + if (d.request_count) { + retcode = mga_dma_get_buffers(dev, &d); + } + + DRM_DEBUG("%d returning, granted = %d\n", + current->pid, d.granted_count); + copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + sarea_priv->last_dispatch = status[1]; + return retcode; +} |