Skip to content

Commit

Permalink
Matrox Mystique: Bus-mastering fixes
Browse files Browse the repository at this point in the history
* Make all bus-mastering-related variables atomic
* Do not, under any circumstances, attempt to read beyond PRIMEND and SECEND

This allows NT 4.0's Mystique drivers to work with busmastering enabled.
  • Loading branch information
Cacodemon345 committed Dec 18, 2023
1 parent 552740b commit 12d5d6c
Showing 1 changed file with 13 additions and 11 deletions.
24 changes: 13 additions & 11 deletions src/video/vid_mga.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
#define FIFO_ADDR 0x00ffffff

#define DMA_POLL_TIME_US 100 /*100us*/
#define DMA_MAX_WORDS 256 /*256 quad words per 100us poll*/
#define DMA_MAX_WORDS (20 * 14) /*280 quad words per 100us poll*/

/*These registers are also mirrored into 0x1dxx, with the mirrored versions starting
the blitter*/
Expand Down Expand Up @@ -505,10 +505,10 @@ typedef struct mystique_t {

struct
{
int pri_pos, sec_pos, iload_pos,
atomic_int pri_pos, sec_pos, iload_pos,
pri_state, sec_state, iload_state, state;

uint32_t primaddress, primend, secaddress, secend,
atomic_uint primaddress, primend, secaddress, secend,
pri_header, sec_header,
iload_header;

Expand Down Expand Up @@ -2660,21 +2660,23 @@ run_dma(mystique_t *mystique)
}

while (words_transferred < DMA_MAX_WORDS && mystique->dma.state != DMA_STATE_IDLE) {
switch (mystique->dma.state) {
switch (atomic_load(&mystique->dma.state)) {
case DMA_STATE_PRI:
switch (mystique->dma.primaddress & DMA_MODE_MASK) {
case DMA_MODE_REG:
if (mystique->dma.pri_state == 0) {
dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.pri_header, 4, 4);
mystique->dma.primaddress += 4;
words_transferred++;
}

if ((mystique->dma.pri_header & 0xff) != 0x15) {
if ((mystique->dma.pri_header & 0xff) != 0x15 || (mystique->dma.primaddress & DMA_ADDR_MASK) < (mystique->dma.primend & DMA_ADDR_MASK)) {
uint32_t val;
uint32_t reg_addr;

dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4);
mystique->dma.primaddress += 4;
words_transferred++;

reg_addr = (mystique->dma.pri_header & 0x7f) << 2;
if (mystique->dma.pri_header & 0x80)
Expand All @@ -2691,10 +2693,9 @@ run_dma(mystique_t *mystique)
mystique->dma.pri_header >>= 8;
mystique->dma.pri_state = (mystique->dma.pri_state + 1) & 3;

words_transferred++;
if (mystique->dma.state == DMA_STATE_SEC)
mystique->dma.pri_state = 0;
else if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
else if ((mystique->dma.primaddress & DMA_ADDR_MASK) >= (mystique->dma.primend & DMA_ADDR_MASK)) {
mystique->endprdmasts_pending = 1;
mystique->dma.state = DMA_STATE_IDLE;
}
Expand All @@ -2711,6 +2712,7 @@ run_dma(mystique_t *mystique)
if (mystique->dma.sec_state == 0) {
dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.sec_header, 4, 4);
mystique->dma.secaddress += 4;
words_transferred++;
}

uint32_t val;
Expand All @@ -2734,8 +2736,8 @@ run_dma(mystique_t *mystique)
mystique->dma.sec_state = (mystique->dma.sec_state + 1) & 3;

words_transferred++;
if ((mystique->dma.secaddress & DMA_ADDR_MASK) == (mystique->dma.secend & DMA_ADDR_MASK)) {
if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) {
if ((mystique->dma.primaddress & DMA_ADDR_MASK) >= (mystique->dma.primend & DMA_ADDR_MASK)) {
mystique->endprdmasts_pending = 1;
mystique->dma.state = DMA_STATE_IDLE;
} else
Expand All @@ -2754,8 +2756,8 @@ run_dma(mystique_t *mystique)
blit_iload_write(mystique, val, 32);

words_transferred++;
if ((mystique->dma.secaddress & DMA_ADDR_MASK) == (mystique->dma.secend & DMA_ADDR_MASK)) {
if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) {
if ((mystique->dma.primaddress & DMA_ADDR_MASK) >= (mystique->dma.primend & DMA_ADDR_MASK)) {
mystique->endprdmasts_pending = 1;
mystique->dma.state = DMA_STATE_IDLE;
} else
Expand Down

0 comments on commit 12d5d6c

Please sign in to comment.