summaryrefslogtreecommitdiff
path: root/linux/mga_dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/mga_dma.c')
-rw-r--r--linux/mga_dma.c413
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);
}