diff options
Diffstat (limited to 'linux/mga_dma.c')
-rw-r--r-- | linux/mga_dma.c | 413 |
1 files changed, 186 insertions, 227 deletions
diff --git a/linux/mga_dma.c b/linux/mga_dma.c index b03544bc..25e3622c 100644 --- a/linux/mga_dma.c +++ b/linux/mga_dma.c @@ -52,6 +52,7 @@ static unsigned long mga_alloc_page(drm_device_t *dev) { unsigned long address; + DRM_DEBUG("%s\n", __FUNCTION__); address = __get_free_page(GFP_KERNEL); if(address == 0UL) { return 0; @@ -64,6 +65,8 @@ static unsigned long mga_alloc_page(drm_device_t *dev) static void mga_free_page(drm_device_t *dev, unsigned long page) { + DRM_DEBUG("%s\n", __FUNCTION__); + if(page == 0UL) { return; } @@ -79,9 +82,11 @@ static void mga_delay(void) return; } -static void mga_flush_write_combine(void) +void mga_flush_write_combine(void) { int xchangeDummy; + DRM_DEBUG("%s\n", __FUNCTION__); + __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 ;" @@ -93,18 +98,6 @@ static void mga_flush_write_combine(void) #define MGA_BUF_USED 0xffffffff #define MGA_BUF_FREE 0 -static void mga_freelist_debug(drm_mga_freelist_t *item) -{ - if(item->buf != NULL) { - DRM_DEBUG("buf index : %d\n", item->buf->idx); - } else { - DRM_DEBUG("Freelist head\n"); - } - DRM_DEBUG("item->age : %x\n", item->age); - DRM_DEBUG("item->next : %p\n", item->next); - DRM_DEBUG("item->prev : %p\n", item->prev); -} - static int mga_freelist_init(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; @@ -113,7 +106,9 @@ static int mga_freelist_init(drm_device_t *dev) drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_mga_freelist_t *item; int i; - + + DRM_DEBUG("%s\n", __FUNCTION__); + dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); if(dev_priv->head == NULL) return -ENOMEM; memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t)); @@ -135,19 +130,10 @@ static int mga_freelist_init(drm_device_t *dev) item->buf = buf; buf_priv->my_freelist = item; buf_priv->discard = 0; + buf_priv->dispatched = 0; dev_priv->head->next = item; } - item = dev_priv->head; - while(item) { - mga_freelist_debug(item); - item = item->next; - } - DRM_DEBUG("Head\n"); - mga_freelist_debug(dev_priv->head); - DRM_DEBUG("Tail\n"); - mga_freelist_debug(dev_priv->tail); - return 0; } @@ -157,6 +143,8 @@ static void mga_freelist_cleanup(drm_device_t *dev) drm_mga_freelist_t *item; drm_mga_freelist_t *prev; + DRM_DEBUG("%s\n", __FUNCTION__); + item = dev_priv->head; while(item) { prev = item; @@ -173,14 +161,14 @@ static inline void mga_dma_quiescent(drm_device_t *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; unsigned long end; int i; + DRM_DEBUG("%s\n", __FUNCTION__); end = jiffies + (HZ*3); while(1) { - if(!test_and_set_bit(0, &dev_priv->dispatch_lock)) { + if(!test_and_set_bit(MGA_IN_DISPATCH, + &dev_priv->dispatch_status)) { break; } if((signed)(end - jiffies) <= 0) { @@ -204,51 +192,25 @@ static inline void mga_dma_quiescent(drm_device_t *dev) } for (i = 0 ; i < 2000 ; i++) mga_delay(); } - DRM_DEBUG("status[1] : %x last_sync_tag : %x\n", status[1], - dev_priv->last_sync_tag); sarea_priv->dirty |= MGA_DMA_FLUSH; out_status: - clear_bit(0, &dev_priv->dispatch_lock); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); out_nolock: } -#define FREELIST_INITIAL (MGA_DMA_BUF_NR * 2) -#define FREELIST_COMPARE(age) ((age >> 2)) - -unsigned int mga_create_sync_tag(drm_device_t *dev) +static void mga_reset_freelist(drm_device_t *dev) { - drm_mga_private_t *dev_priv = - (drm_mga_private_t *) dev->dev_private; - unsigned int temp; - drm_buf_t *buf; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; drm_mga_buf_priv_t *buf_priv; - drm_device_dma_t *dma = dev->dma; - int i; - - dev_priv->sync_tag++; - - if(dev_priv->sync_tag < FREELIST_INITIAL) { - dev_priv->sync_tag = FREELIST_INITIAL; - } - if(dev_priv->sync_tag > 0x3fffffff) { - mga_flush_queue(dev); - mga_dma_quiescent(dev); - - for (i = 0; i < dma->buf_count; i++) { - buf = dma->buflist[ i ]; - buf_priv = buf->dev_private; - buf_priv->my_freelist->age = MGA_BUF_FREE; - } - - dev_priv->sync_tag = FREELIST_INITIAL; - } - temp = dev_priv->sync_tag << 2; - - dev_priv->sarea_priv->last_enqueue = temp; + int i; - DRM_DEBUG("sync_tag : %x\n", temp); - return temp; + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[ i ]; + buf_priv = buf->dev_private; + buf_priv->my_freelist->age = MGA_BUF_FREE; + } } /* Least recently used : @@ -257,23 +219,52 @@ unsigned int mga_create_sync_tag(drm_device_t *dev) drm_buf_t *mga_freelist_get(drm_device_t *dev) { + DECLARE_WAITQUEUE(entry, current); drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; drm_mga_freelist_t *prev; drm_mga_freelist_t *next; + static int failed = 0; + + DRM_DEBUG("%s : tail->age : %d last_prim_age : %d\n", __FUNCTION__, + dev_priv->tail->age, dev_priv->last_prim_age); - if((dev_priv->tail->age >> 2) <= FREELIST_COMPARE(status[1])) { + if(failed >= 1000 && dev_priv->tail->age >= dev_priv->last_prim_age) { + DRM_DEBUG("I'm waiting on the freelist!!! %d\n", + dev_priv->last_prim_age); + set_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->buf_queue, &entry); + for (;;) { + mga_dma_schedule(dev, 0); + if(!test_bit(MGA_IN_GETBUF, + &dev_priv->dispatch_status)) + break; + atomic_inc(&dev->total_sleeps); + schedule(); + if (signal_pending(current)) { + clear_bit(MGA_IN_GETBUF, + &dev_priv->dispatch_status); + goto failed_getbuf; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->buf_queue, &entry); + } + + if(dev_priv->tail->age < dev_priv->last_prim_age) { prev = dev_priv->tail->prev; next = dev_priv->tail; prev->next = NULL; next->prev = next->next = NULL; dev_priv->tail = prev; next->age = MGA_BUF_USED; + failed = 0; return next->buf; - } + } +failed_getbuf: + failed++; return NULL; } @@ -286,6 +277,8 @@ int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf) drm_mga_freelist_t *head; drm_mga_freelist_t *next; + DRM_DEBUG("%s\n", __FUNCTION__); + if(buf_priv->my_freelist->age == MGA_BUF_USED) { /* Discarded buffer, put it on the tail */ next = buf_priv->my_freelist; @@ -312,32 +305,6 @@ int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf) return 0; } -static void mga_print_all_primary(drm_device_t *dev) -{ - drm_mga_private_t *dev_priv = dev->dev_private; - drm_mga_prim_buf_t *prim; - int i; - - DRM_DEBUG("Full list of primarys\n"); - for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { - prim = dev_priv->prim_bufs[i]; - DRM_DEBUG("index : %d num_dwords : %d " - "max_dwords : %d phy_head : %x\n", - prim->idx, prim->num_dwords, - prim->max_dwords, prim->phys_head); - DRM_DEBUG("sec_used : %d swap_pending : %x " - "in_use : %x force_fire : %d\n", - prim->sec_used, prim->swap_pending, - prim->in_use, atomic_read(&prim->force_fire)); - DRM_DEBUG("needs_overflow : %d\n", - atomic_read(&prim->needs_overflow)); - } - - DRM_DEBUG("current_idx : %d, next_idx : %d, last_idx : %d\n", - dev_priv->next_prim->idx, dev_priv->last_prim->idx, - dev_priv->current_prim->idx); -} - static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) { drm_mga_private_t *dev_priv = dev->dev_private; @@ -345,10 +312,9 @@ static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) int i, temp, size_of_buf; int offset = init->reserved_map_agpstart; - DRM_DEBUG("mga_init_primary_bufs\n"); + DRM_DEBUG("%s\n", __FUNCTION__); 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 *) * @@ -358,18 +324,12 @@ static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) 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); - DRM_DEBUG("ioremap\n"); dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, temp); if(dev_priv->ioremap == NULL) { @@ -379,11 +339,9 @@ static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) 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 = @@ -396,17 +354,18 @@ static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) prim_buffer->max_dwords -= 5; /* Leave room for the softrap */ prim_buffer->sec_used = 0; prim_buffer->idx = i; + prim_buffer->prim_age = i + 1; 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"); + dev_priv->next_prim_age = 2; + dev_priv->last_prim_age = 1; + set_bit(MGA_BUF_IN_USE, &dev_priv->current_prim->buffer_status); return 0; } @@ -420,9 +379,8 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) int i; int next_idx; PRIMLOCALS; - - DRM_DEBUG("mga_fire_primary\n"); - dev_priv->last_sync_tag = mga_create_sync_tag(dev); + + DRM_DEBUG("%s\n", __FUNCTION__); dev_priv->last_prim = prim; /* We never check for overflow, b/c there is always room */ @@ -433,7 +391,7 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) } PRIMOUTREG( MGAREG_DMAPAD, 0); PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMOUTREG( MGAREG_DMAPAD, 0); PRIMOUTREG( MGAREG_SOFTRAP, 0); PRIMFINISH(prim); @@ -468,13 +426,13 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) for (i = 0 ; i < 4096 ; i++) mga_delay(); } } - + mga_flush_write_combine(); atomic_inc(&dev_priv->pending_bufs); - atomic_inc(&dma->total_lost); MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); prim->num_dwords = 0; + sarea_priv->last_enqueue = prim->prim_age; next_idx = prim->idx + 1; if(next_idx >= MGA_NUM_PRIM_BUFS) @@ -486,11 +444,10 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) out_prim_wait: prim->num_dwords = 0; prim->sec_used = 0; - clear_bit(0, &prim->in_use); + clear_bit(MGA_BUF_IN_USE, &prim->buffer_status); wake_up_interruptible(&dev_priv->wait_queue); - clear_bit(0, &prim->swap_pending); - clear_bit(0, &dev_priv->dispatch_lock); - atomic_dec(&dev_priv->pending_bufs); + clear_bit(MGA_BUF_SWAP_PENDING, &prim->buffer_status); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); } int mga_advance_primary(drm_device_t *dev) @@ -505,27 +462,28 @@ int mga_advance_primary(drm_device_t *dev) /* This needs to reset the primary buffer if available, * we should collect stats on how many times it bites * it's tail */ + DRM_DEBUG("%s\n", __FUNCTION__); 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]; - atomic_set(&dev_priv->in_wait, 1); + set_bit(MGA_IN_WAIT, &dev_priv->dispatch_status); /* In use is cleared in interrupt handler */ - if(test_and_set_bit(0, &prim_buffer->in_use)) { + if(test_and_set_bit(MGA_BUF_IN_USE, &prim_buffer->buffer_status)) { add_wait_queue(&dev_priv->wait_queue, &entry); + current->state = TASK_INTERRUPTIBLE; + for (;;) { - current->state = TASK_INTERRUPTIBLE; mga_dma_schedule(dev, 0); - if(!test_and_set_bit(0, &prim_buffer->in_use)) break; + if(!test_and_set_bit(MGA_BUF_IN_USE, + &prim_buffer->buffer_status)) + break; atomic_inc(&dev->total_sleeps); atomic_inc(&dma->total_missed_sched); - mga_print_all_primary(dev); - DRM_DEBUG("Schedule in advance\n"); - /* Three second delay */ - schedule_timeout(HZ*3); + schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; break; @@ -535,16 +493,27 @@ int mga_advance_primary(drm_device_t *dev) remove_wait_queue(&dev_priv->wait_queue, &entry); if(ret) return ret; } - atomic_set(&dev_priv->in_wait, 0); + clear_bit(MGA_IN_WAIT, &dev_priv->dispatch_status); + /* 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; - atomic_set(&prim_buffer->needs_overflow, 0); + prim_buffer->prim_age = dev_priv->next_prim_age++; + if(prim_buffer->prim_age == 0 || prim_buffer->prim_age == 0xffffffff) { + mga_flush_queue(dev); + mga_dma_quiescent(dev); + mga_reset_freelist(dev); + prim_buffer->prim_age = (dev_priv->next_prim_age += 2); + } + + /* Reset all buffer status stuff */ + clear_bit(MGA_BUF_NEEDS_OVERFLOW, &prim_buffer->buffer_status); + clear_bit(MGA_BUF_FORCE_FIRE, &prim_buffer->buffer_status); + clear_bit(MGA_BUF_SWAP_PENDING, &prim_buffer->buffer_status); + dev_priv->current_prim = prim_buffer; dev_priv->current_prim_idx = next_prim_idx; - DRM_DEBUG("Primarys at advance\n"); - mga_print_all_primary(dev); return 0; } @@ -553,21 +522,29 @@ static inline int mga_decide_to_fire(drm_device_t *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_device_dma_t *dma = dev->dma; - - if(atomic_read(&dev_priv->next_prim->force_fire)) - { + + DRM_DEBUG("%s\n", __FUNCTION__); + + if(test_bit(MGA_BUF_FORCE_FIRE, &dev_priv->next_prim->buffer_status)) { atomic_inc(&dma->total_prio); return 1; } - if (atomic_read(&dev_priv->in_flush) && dev_priv->next_prim->num_dwords) - { + if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords) { + atomic_inc(&dma->total_prio); + return 1; + } + + if (test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords) { atomic_inc(&dma->total_prio); return 1; } if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS - 1) { - if(test_bit(0, &dev_priv->next_prim->swap_pending)) { + if(test_bit(MGA_BUF_SWAP_PENDING, + &dev_priv->next_prim->buffer_status)) { atomic_inc(&dma->total_dmas); return 1; } @@ -601,10 +578,11 @@ int mga_dma_schedule(drm_device_t *dev, int locked) return -EBUSY; } - DRM_DEBUG("mga_dma_schedule\n"); + DRM_DEBUG("%s\n", __FUNCTION__); - if(atomic_read(&dev_priv->in_flush) || - atomic_read(&dev_priv->in_wait)) { + if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) || + test_bit(MGA_IN_WAIT, &dev_priv->dispatch_status) || + test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) { locked = 1; } @@ -612,27 +590,25 @@ int mga_dma_schedule(drm_device_t *dev, int locked) !drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { atomic_inc(&dma->total_missed_lock); clear_bit(0, &dev->dma_flag); + DRM_DEBUG("Not locked\n"); return -EBUSY; } DRM_DEBUG("I'm locked\n"); - - if(!test_and_set_bit(0, &dev_priv->dispatch_lock)) { + if(!test_and_set_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status)) { /* Fire dma buffer */ if(mga_decide_to_fire(dev)) { - DRM_DEBUG("mga_fire_primary\n"); DRM_DEBUG("idx :%d\n", dev_priv->next_prim->idx); - atomic_set(&dev_priv->next_prim->force_fire, 0); - if(dev_priv->current_prim == dev_priv->next_prim && - dev_priv->next_prim->num_dwords != 0) { + clear_bit(MGA_BUF_FORCE_FIRE, + &dev_priv->next_prim->buffer_status); + if(dev_priv->current_prim == dev_priv->next_prim) { /* Schedule overflow for a later time */ - atomic_set( - &dev_priv->current_prim->needs_overflow, - 1); + set_bit(MGA_BUF_NEEDS_OVERFLOW, + &dev_priv->next_prim->buffer_status); } mga_fire_primary(dev, dev_priv->next_prim); } else { - clear_bit(0, &dev_priv->dispatch_lock); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); } } else { DRM_DEBUG("I can't get the dispatch lock\n"); @@ -645,17 +621,26 @@ int mga_dma_schedule(drm_device_t *dev, int locked) } } - clear_bit(0, &dev->dma_flag); - - if(atomic_read(&dev_priv->in_flush) == 1 && - dev_priv->next_prim->num_dwords == 0) { - /* Everything is on the hardware */ - DRM_DEBUG("Primarys at Flush\n"); - mga_print_all_primary(dev); - atomic_set(&dev_priv->in_flush, 0); + if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords == 0 && + atomic_read(&dev_priv->pending_bufs) == 0) { + /* Everything has been processed by the hardware */ + clear_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status); wake_up_interruptible(&dev_priv->flush_queue); } + if(test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) && + dev_priv->tail->age < dev_priv->last_prim_age) { + clear_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); + DRM_DEBUG("Waking up buf queue\n"); + wake_up_interruptible(&dev_priv->buf_queue); + } else if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) { + DRM_DEBUG("Not waking buf_queue on %d %d\n", + atomic_read(&dev->total_irq), + dev_priv->last_prim_age); + } + + clear_bit(0, &dev->dma_flag); return 0; } @@ -664,33 +649,35 @@ 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; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; - + + DRM_DEBUG("%s\n", __FUNCTION__); atomic_inc(&dev->total_irq); + if((MGA_READ(MGAREG_STATUS) & 0x00000001) != 0x00000001) return; MGA_WRITE(MGAREG_ICLEAR, 0x00000001); last_prim_buffer = dev_priv->last_prim; last_prim_buffer->num_dwords = 0; last_prim_buffer->sec_used = 0; - clear_bit(0, &last_prim_buffer->in_use); + dev_priv->sarea_priv->last_dispatch = + dev_priv->last_prim_age = last_prim_buffer->prim_age; + clear_bit(MGA_BUF_IN_USE, &last_prim_buffer->buffer_status); wake_up_interruptible(&dev_priv->wait_queue); - clear_bit(0, &last_prim_buffer->swap_pending); - clear_bit(0, &dev_priv->dispatch_lock); + clear_bit(MGA_BUF_SWAP_PENDING, &last_prim_buffer->buffer_status); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); atomic_dec(&dev_priv->pending_bufs); - dev_priv->sarea_priv->last_dispatch = status[1]; queue_task(&dev->tq, &tq_immediate); mark_bh(IMMEDIATE_BH); } static void mga_dma_task_queue(void *device) { - drm_device_t *dev = (drm_device_t *) device; - - mga_dma_schedule(dev, 0); + DRM_DEBUG("%s\n", __FUNCTION__); + mga_dma_schedule((drm_device_t *)device, 0); } int mga_dma_cleanup(drm_device_t *dev) { + DRM_DEBUG("%s\n", __FUNCTION__); + if(dev->dev_private) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; @@ -739,14 +726,13 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { drm_map_t *sarea_map = NULL; int i; + DRM_DEBUG("%s\n", __FUNCTION__); + dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); if(dev_priv == NULL) return -ENOMEM; dev->dev_private = (void *) dev_priv; - DRM_DEBUG("dev_private\n"); - memset(dev_priv, 0, sizeof(drm_mga_private_t)); - atomic_set(&dev_priv->in_flush, 0); if((init->reserved_map_idx >= dev->map_count) || (init->buffer_map_idx >= dev->map_count)) { @@ -761,7 +747,6 @@ 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"); /* Scale primary size to the next page */ dev_priv->chipset = init->chipset; @@ -776,6 +761,7 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { dev_priv->mAccess = init->mAccess; init_waitqueue_head(&dev_priv->flush_queue); + init_waitqueue_head(&dev_priv->buf_queue); dev_priv->WarpPipe = -1; DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n", @@ -795,20 +781,17 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { dev_priv->WarpIndex[i].phys_addr, dev_priv->WarpIndex[i].size); - 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; } - 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); DRM_ERROR("Can not allocate status page\n"); return -ENOMEM; } - DRM_DEBUG("Status page at %lx\n", dev_priv->real_status_page); dev_priv->status_page = ioremap_nocache(virt_to_bus((void *)dev_priv->real_status_page), @@ -820,38 +803,23 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { return -ENOMEM; } - DRM_DEBUG("Status page remapped to %p\n", dev_priv->status_page); /* Write status page when secend or softrap occurs */ MGA_WRITE(MGAREG_PRIMPTR, virt_to_bus((void *)dev_priv->real_status_page) | 0x00000003); - - dev_priv->device = pci_find_device(0x102b, 0x0525, NULL); - if(dev_priv->device == NULL) { - DRM_ERROR("Could not find pci device for card\n"); - mga_dma_cleanup(dev); - return -EINVAL; - } - - DRM_DEBUG("dma initialization\n"); + /* Private is now filled in, initialize the hardware */ { - __volatile__ unsigned int *status = - (unsigned int *)dev_priv->status_page; PRIMLOCALS; PRIMGETPTR( dev_priv ); - - dev_priv->last_sync_tag = mga_create_sync_tag(dev); - + PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMOUTREG(MGAREG_DWGSYNC, 0x0100); PRIMOUTREG(MGAREG_SOFTRAP, 0); /* 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); @@ -859,9 +827,7 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | PDEA_pagpxfer_enable)); - 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]); + while(MGA_READ(MGAREG_DWGSYNC) != 0x0100) ; } if(mga_freelist_init(dev) != 0) { @@ -869,7 +835,6 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { mga_dma_cleanup(dev); return -ENOMEM; } - DRM_DEBUG("dma init was successful\n"); return 0; } @@ -880,6 +845,8 @@ int mga_dma_init(struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; drm_mga_init_t init; + DRM_DEBUG("%s\n", __FUNCTION__); + copy_from_user_ret(&init, (drm_mga_init_t *)arg, sizeof(init), -EFAULT); switch(init.func) { @@ -924,7 +891,7 @@ int mga_irq_install(drm_device_t *dev, int irq) /* Install handler */ if ((retcode = request_irq(dev->irq, mga_dma_service, - 0, + SA_SHIRQ, dev->devname, dev))) { down(&dev->struct_sem); @@ -963,7 +930,9 @@ int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, drm_control_t ctl; copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); - + + DRM_DEBUG("%s\n", __FUNCTION__); + switch (ctl.func) { case DRM_INST_HANDLER: return mga_irq_install(dev, ctl.irq); @@ -980,30 +949,33 @@ static int mga_flush_queue(drm_device_t *dev) drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; int ret = 0; + DRM_DEBUG("%s\n", __FUNCTION__); + if(dev_priv == NULL) { return 0; } if(dev_priv->next_prim->num_dwords != 0) { - atomic_set(&dev_priv->in_flush, 1); + set_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status); current->state = TASK_INTERRUPTIBLE; add_wait_queue(&dev_priv->flush_queue, &entry); for (;;) { mga_dma_schedule(dev, 0); - if (atomic_read(&dev_priv->in_flush) == 0) + if (!test_bit(MGA_IN_FLUSH, + &dev_priv->dispatch_status)) break; atomic_inc(&dev->total_sleeps); - DRM_DEBUG("Schedule in flush_queue\n"); - schedule_timeout(HZ*3); + schedule(); if (signal_pending(current)) { ret = -EINTR; /* Can't restart */ + clear_bit(MGA_IN_FLUSH, + &dev_priv->dispatch_status); break; } } current->state = TASK_RUNNING; remove_wait_queue(&dev_priv->flush_queue, &entry); } - atomic_set(&dev_priv->in_flush, 0); return ret; } @@ -1017,6 +989,7 @@ void mga_reclaim_buffers(drm_device_t *dev, pid_t pid) if(dev->dev_private == NULL) return; if(dma->buflist == NULL) return; + DRM_DEBUG("%s\n", __FUNCTION__); mga_flush_queue(dev); for (i = 0; i < dma->buf_count; i++) { @@ -1042,6 +1015,7 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, int ret = 0; drm_lock_t lock; + DRM_DEBUG("%s\n", __FUNCTION__); copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); if (lock.context == DRM_KERNEL_CONTEXT) { @@ -1080,7 +1054,6 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; - DRM_DEBUG("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; @@ -1110,11 +1083,8 @@ int mga_flush_ioctl(struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; drm_lock_t lock; 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 i; - + + DRM_DEBUG("%s\n", __FUNCTION__); copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { @@ -1123,28 +1093,17 @@ int mga_flush_ioctl(struct inode *inode, struct file *filp, } if(lock.flags & _DRM_LOCK_FLUSH || lock.flags & _DRM_LOCK_FLUSH_ALL) { - mga_flush_queue(dev); - - if((MGA_READ(MGAREG_STATUS) & 0x00030001) == 0x00020000 && - status[1] != dev_priv->last_sync_tag) - { - DRM_DEBUG("Reseting hardware status\n"); - MGA_WRITE(MGAREG_DWGSYNC, dev_priv->last_sync_tag); - - while(MGA_READ(MGAREG_DWGSYNC) != - dev_priv->last_sync_tag) - { - for(i = 0; i < 4096; i++) mga_delay(); - } - - status[1] = - sarea_priv->last_dispatch = - dev_priv->last_sync_tag; - } else { - sarea_priv->last_dispatch = status[1]; - } + drm_mga_prim_buf_t *temp_buf = + dev_priv->prim_bufs[dev_priv->current_prim_idx]; + + if(temp_buf && temp_buf->num_dwords) { + set_bit(MGA_BUF_FORCE_FIRE, &temp_buf->buffer_status); + mga_advance_primary(dev); + mga_dma_schedule(dev, 1); + } } if(lock.flags & _DRM_LOCK_QUIESCENT) { + mga_flush_queue(dev); mga_dma_quiescent(dev); } |