mirror of https://github.com/xemu-project/xemu.git
maybe slightly less racey
This commit is contained in:
parent
0ca0cc251d
commit
e91dff0bed
145
hw/xbox/nv2a.c
145
hw/xbox/nv2a.c
|
@ -246,6 +246,10 @@
|
|||
# define NV_PGRAPH_TRAPPED_ADDR_CHID 0x01F00000
|
||||
# define NV_PGRAPH_TRAPPED_ADDR_DHV 0x10000000
|
||||
#define NV_PGRAPH_TRAPPED_DATA_LOW 0x00000708
|
||||
#define NV_PGRAPH_SURFACE 0x00000710
|
||||
# define NV_PGRAPH_SURFACE_WRITE_3D 0x00700000
|
||||
# define NV_PGRAPH_SURFACE_READ_3D 0x07000000
|
||||
# define NV_PGRAPH_SURFACE_MODULO_3D 0x70000000
|
||||
#define NV_PGRAPH_INCREMENT 0x0000071C
|
||||
# define NV_PGRAPH_INCREMENT_READ_BLIT (1 << 0)
|
||||
# define NV_PGRAPH_INCREMENT_READ_3D (1 << 1)
|
||||
|
@ -489,6 +493,10 @@
|
|||
#define NV_KELVIN_PRIMITIVE 0x0097
|
||||
# define NV097_NO_OPERATION 0x00970100
|
||||
# define NV097_WAIT_FOR_IDLE 0x00970110
|
||||
# define NV097_SET_FLIP_READ 0x00970120
|
||||
# define NV097_SET_FLIP_WRITE 0x00970124
|
||||
# define NV097_SET_FLIP_MODULO 0x00970128
|
||||
# define NV097_FLIP_INCREMENT_WRITE 0x0097012C
|
||||
# define NV097_FLIP_STALL 0x00970130
|
||||
# define NV097_SET_CONTEXT_DMA_NOTIFIES 0x00970180
|
||||
# define NV097_SET_CONTEXT_DMA_A 0x00970184
|
||||
|
@ -1019,10 +1027,6 @@ typedef struct Cache1State {
|
|||
uint32_t data_shadow;
|
||||
uint32_t error;
|
||||
|
||||
|
||||
/* Puller state */
|
||||
QemuMutex pull_lock;
|
||||
|
||||
bool pull_enabled;
|
||||
enum FIFOEngine bound_engines[NV2A_NUM_SUBCHANNELS];
|
||||
enum FIFOEngine last_engine;
|
||||
|
@ -1045,10 +1049,14 @@ typedef struct ChannelControl {
|
|||
typedef struct NV2AState {
|
||||
PCIDevice dev;
|
||||
qemu_irq irq;
|
||||
|
||||
bool exiting;
|
||||
|
||||
VGACommonState vga;
|
||||
GraphicHwOps hw_ops;
|
||||
|
||||
QEMUTimer *vblank_timer;
|
||||
|
||||
MemoryRegion *vram;
|
||||
MemoryRegion vram_pci;
|
||||
uint8_t *vram_ptr;
|
||||
|
@ -1160,6 +1168,7 @@ static void update_irq(NV2AState *d)
|
|||
}
|
||||
|
||||
if (d->pmc.pending_interrupts && d->pmc.enabled_interrupts) {
|
||||
NV2A_DPRINTF("raise irq\n");
|
||||
pci_irq_assert(&d->dev);
|
||||
} else {
|
||||
pci_irq_deassert(&d->dev);
|
||||
|
@ -2381,12 +2390,45 @@ static void pgraph_method(NV2AState *d,
|
|||
pgraph_update_surface(d, false);
|
||||
break;
|
||||
|
||||
|
||||
case NV097_SET_FLIP_READ:
|
||||
SET_MASK(pg->regs[NV_PGRAPH_SURFACE], NV_PGRAPH_SURFACE_READ_3D,
|
||||
parameter);
|
||||
break;
|
||||
case NV097_SET_FLIP_WRITE:
|
||||
SET_MASK(pg->regs[NV_PGRAPH_SURFACE], NV_PGRAPH_SURFACE_WRITE_3D,
|
||||
parameter);
|
||||
break;
|
||||
case NV097_SET_FLIP_MODULO:
|
||||
SET_MASK(pg->regs[NV_PGRAPH_SURFACE], NV_PGRAPH_SURFACE_MODULO_3D,
|
||||
parameter);
|
||||
break;
|
||||
case NV097_FLIP_INCREMENT_WRITE: {
|
||||
SET_MASK(pg->regs[NV_PGRAPH_SURFACE],
|
||||
NV_PGRAPH_SURFACE_WRITE_3D,
|
||||
(GET_MASK(pg->regs[NV_PGRAPH_SURFACE],
|
||||
NV_PGRAPH_SURFACE_WRITE_3D)+1)
|
||||
% GET_MASK(pg->regs[NV_PGRAPH_SURFACE],
|
||||
NV_PGRAPH_SURFACE_MODULO_3D) );
|
||||
break;
|
||||
}
|
||||
case NV097_FLIP_STALL:
|
||||
pgraph_update_surface(d, false);
|
||||
|
||||
qemu_mutex_unlock(&pg->lock);
|
||||
qemu_sem_wait(&pg->read_3d);
|
||||
qemu_mutex_lock(&pg->lock);
|
||||
|
||||
// busy-wait for now...
|
||||
while (true) {
|
||||
qemu_mutex_lock(&pg->lock);
|
||||
|
||||
uint32_t s = pg->regs[NV_PGRAPH_SURFACE];
|
||||
if (GET_MASK(s, NV_PGRAPH_SURFACE_READ_3D)
|
||||
== GET_MASK(s, NV_PGRAPH_SURFACE_WRITE_3D)) {
|
||||
break;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&pg->lock);
|
||||
}
|
||||
break;
|
||||
|
||||
case NV097_SET_CONTEXT_DMA_NOTIFIES:
|
||||
|
@ -3044,7 +3086,7 @@ static void pgraph_wait_fifo_access(NV2AState *d) {
|
|||
qemu_mutex_unlock(&d->pgraph.lock);
|
||||
}
|
||||
|
||||
static void *pfifo_puller_thread(void *arg)
|
||||
static void* pfifo_puller_thread(void *arg)
|
||||
{
|
||||
NV2AState *d = arg;
|
||||
Cache1State *state = &d->pfifo.cache1;
|
||||
|
@ -3052,25 +3094,14 @@ static void *pfifo_puller_thread(void *arg)
|
|||
RAMHTEntry entry;
|
||||
|
||||
while (true) {
|
||||
qemu_mutex_lock(&state->pull_lock);
|
||||
if (!state->pull_enabled) {
|
||||
qemu_mutex_unlock(&state->pull_lock);
|
||||
return NULL;
|
||||
}
|
||||
qemu_mutex_unlock(&state->pull_lock);
|
||||
|
||||
qemu_mutex_lock(&state->cache_lock);
|
||||
while (QSIMPLEQ_EMPTY(&state->cache)) {
|
||||
while (QSIMPLEQ_EMPTY(&state->cache) || !state->pull_enabled) {
|
||||
qemu_cond_wait(&state->cache_cond, &state->cache_lock);
|
||||
|
||||
/* we could have been woken up to tell us we should die */
|
||||
qemu_mutex_lock(&state->pull_lock);
|
||||
if (!state->pull_enabled) {
|
||||
qemu_mutex_unlock(&state->pull_lock);
|
||||
if (d->exiting) {
|
||||
qemu_mutex_unlock(&state->cache_lock);
|
||||
return NULL;
|
||||
}
|
||||
qemu_mutex_unlock(&state->pull_lock);
|
||||
}
|
||||
command = QSIMPLEQ_FIRST(&state->cache);
|
||||
QSIMPLEQ_REMOVE_HEAD(&state->cache, entry);
|
||||
|
@ -3097,10 +3128,10 @@ static void *pfifo_puller_thread(void *arg)
|
|||
}
|
||||
|
||||
/* the engine is bound to the subchannel */
|
||||
qemu_mutex_lock(&state->pull_lock);
|
||||
qemu_mutex_lock(&state->cache_lock);
|
||||
state->bound_engines[command->subchannel] = entry.engine;
|
||||
state->last_engine = entry.engine;
|
||||
qemu_mutex_unlock(&state->pull_lock);
|
||||
qemu_mutex_unlock(&state->cache_lock);
|
||||
} else if (command->method >= 0x100) {
|
||||
/* method passed to engine */
|
||||
|
||||
|
@ -3117,9 +3148,9 @@ static void *pfifo_puller_thread(void *arg)
|
|||
//qemu_mutex_unlock_iothread();
|
||||
}
|
||||
|
||||
qemu_mutex_lock(&state->pull_lock);
|
||||
qemu_mutex_lock(&state->cache_lock);
|
||||
enum FIFOEngine engine = state->bound_engines[command->subchannel];
|
||||
qemu_mutex_unlock(&state->pull_lock);
|
||||
qemu_mutex_unlock(&state->cache_lock);
|
||||
|
||||
switch (engine) {
|
||||
case ENGINE_GRAPHICS:
|
||||
|
@ -3132,9 +3163,9 @@ static void *pfifo_puller_thread(void *arg)
|
|||
break;
|
||||
}
|
||||
|
||||
qemu_mutex_lock(&state->pull_lock);
|
||||
qemu_mutex_lock(&state->cache_lock);
|
||||
state->last_engine = state->bound_engines[command->subchannel];
|
||||
qemu_mutex_unlock(&state->pull_lock);
|
||||
qemu_mutex_unlock(&state->cache_lock);
|
||||
}
|
||||
|
||||
g_free(command);
|
||||
|
@ -3266,6 +3297,9 @@ static void pfifo_run_pusher(NV2AState *d) {
|
|||
}
|
||||
}
|
||||
|
||||
NV2A_DPRINTF("DMA pusher done: max 0x%llx, 0x%llx - 0x%llx\n",
|
||||
dma_len, control->dma_get, control->dma_put);
|
||||
|
||||
if (state->error) {
|
||||
NV2A_DPRINTF("pb error: %d\n", state->error);
|
||||
assert(false);
|
||||
|
@ -3459,16 +3493,16 @@ static uint64_t pfifo_read(void *opaque,
|
|||
| d->pfifo.cache1.subroutine_active;
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PULL0:
|
||||
qemu_mutex_lock(&d->pfifo.cache1.pull_lock);
|
||||
qemu_mutex_lock(&d->pfifo.cache1.cache_lock);
|
||||
r = d->pfifo.cache1.pull_enabled;
|
||||
qemu_mutex_unlock(&d->pfifo.cache1.pull_lock);
|
||||
qemu_mutex_unlock(&d->pfifo.cache1.cache_lock);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_ENGINE:
|
||||
qemu_mutex_lock(&d->pfifo.cache1.pull_lock);
|
||||
qemu_mutex_lock(&d->pfifo.cache1.cache_lock);
|
||||
for (i=0; i<NV2A_NUM_SUBCHANNELS; i++) {
|
||||
r |= d->pfifo.cache1.bound_engines[i] << (i*2);
|
||||
}
|
||||
qemu_mutex_unlock(&d->pfifo.cache1.pull_lock);
|
||||
qemu_mutex_unlock(&d->pfifo.cache1.cache_lock);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_DCOUNT:
|
||||
r = d->pfifo.cache1.dcount;
|
||||
|
@ -3574,30 +3608,25 @@ static void pfifo_write(void *opaque, hwaddr addr,
|
|||
(val & NV_PFIFO_CACHE1_DMA_SUBROUTINE_STATE);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_PULL0:
|
||||
qemu_mutex_lock(&d->pfifo.cache1.pull_lock);
|
||||
qemu_mutex_lock(&d->pfifo.cache1.cache_lock);
|
||||
if ((val & NV_PFIFO_CACHE1_PULL0_ACCESS)
|
||||
&& !d->pfifo.cache1.pull_enabled) {
|
||||
d->pfifo.cache1.pull_enabled = true;
|
||||
|
||||
/* fire up puller thread */
|
||||
qemu_thread_create(&d->pfifo.puller_thread,
|
||||
pfifo_puller_thread,
|
||||
d, QEMU_THREAD_DETACHED);
|
||||
/* the puller thread should wake up */
|
||||
qemu_cond_signal(&d->pfifo.cache1.cache_cond);
|
||||
} else if (!(val & NV_PFIFO_CACHE1_PULL0_ACCESS)
|
||||
&& d->pfifo.cache1.pull_enabled) {
|
||||
d->pfifo.cache1.pull_enabled = false;
|
||||
|
||||
/* the puller thread should die, wake it up. */
|
||||
qemu_cond_broadcast(&d->pfifo.cache1.cache_cond);
|
||||
}
|
||||
qemu_mutex_unlock(&d->pfifo.cache1.pull_lock);
|
||||
qemu_mutex_unlock(&d->pfifo.cache1.cache_lock);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_ENGINE:
|
||||
qemu_mutex_lock(&d->pfifo.cache1.pull_lock);
|
||||
qemu_mutex_lock(&d->pfifo.cache1.cache_lock);
|
||||
for (i=0; i<NV2A_NUM_SUBCHANNELS; i++) {
|
||||
d->pfifo.cache1.bound_engines[i] = (val >> (i*2)) & 3;
|
||||
}
|
||||
qemu_mutex_unlock(&d->pfifo.cache1.pull_lock);
|
||||
qemu_mutex_unlock(&d->pfifo.cache1.cache_lock);
|
||||
break;
|
||||
case NV_PFIFO_CACHE1_DMA_DCOUNT:
|
||||
d->pfifo.cache1.dcount =
|
||||
|
@ -3891,7 +3920,9 @@ static uint64_t pgraph_read(void *opaque,
|
|||
uint64_t r = 0;
|
||||
switch (addr) {
|
||||
case NV_PGRAPH_INTR:
|
||||
qemu_mutex_lock(&d->pgraph.lock);
|
||||
r = d->pgraph.pending_interrupts;
|
||||
qemu_mutex_unlock(&d->pgraph.lock);
|
||||
break;
|
||||
case NV_PGRAPH_INTR_EN:
|
||||
r = d->pgraph.enabled_interrupts;
|
||||
|
@ -3950,36 +3981,35 @@ static void pgraph_write(void *opaque, hwaddr addr,
|
|||
|
||||
reg_log_write(NV_PGRAPH, addr, val);
|
||||
|
||||
qemu_mutex_lock(&d->pgraph.lock);
|
||||
|
||||
switch (addr) {
|
||||
case NV_PGRAPH_INTR:
|
||||
qemu_mutex_lock(&d->pgraph.lock);
|
||||
d->pgraph.pending_interrupts &= ~val;
|
||||
qemu_cond_broadcast(&d->pgraph.interrupt_cond);
|
||||
qemu_mutex_unlock(&d->pgraph.lock);
|
||||
break;
|
||||
case NV_PGRAPH_INTR_EN:
|
||||
d->pgraph.enabled_interrupts = val;
|
||||
break;
|
||||
case NV_PGRAPH_CTX_CONTROL:
|
||||
qemu_mutex_lock(&d->pgraph.lock);
|
||||
d->pgraph.channel_valid = (val & NV_PGRAPH_CTX_CONTROL_CHID);
|
||||
qemu_mutex_unlock(&d->pgraph.lock);
|
||||
break;
|
||||
case NV_PGRAPH_CTX_USER:
|
||||
qemu_mutex_lock(&d->pgraph.lock);
|
||||
pgraph_set_context_user(d, val);
|
||||
qemu_mutex_unlock(&d->pgraph.lock);
|
||||
break;
|
||||
case NV_PGRAPH_INCREMENT:
|
||||
if (val & NV_PGRAPH_INCREMENT_READ_3D) {
|
||||
qemu_sem_post(&d->pgraph.read_3d);
|
||||
SET_MASK(d->pgraph.regs[NV_PGRAPH_SURFACE],
|
||||
NV_PGRAPH_SURFACE_READ_3D,
|
||||
(GET_MASK(d->pgraph.regs[NV_PGRAPH_SURFACE],
|
||||
NV_PGRAPH_SURFACE_READ_3D)+1)
|
||||
% GET_MASK(d->pgraph.regs[NV_PGRAPH_SURFACE],
|
||||
NV_PGRAPH_SURFACE_MODULO_3D) );
|
||||
}
|
||||
break;
|
||||
case NV_PGRAPH_FIFO:
|
||||
qemu_mutex_lock(&d->pgraph.lock);
|
||||
d->pgraph.fifo_access = GET_MASK(val, NV_PGRAPH_FIFO_ACCESS);
|
||||
qemu_cond_broadcast(&d->pgraph.fifo_access_cond);
|
||||
qemu_mutex_unlock(&d->pgraph.lock);
|
||||
break;
|
||||
case NV_PGRAPH_CHANNEL_CTX_TABLE:
|
||||
d->pgraph.context_table =
|
||||
|
@ -3990,7 +4020,6 @@ static void pgraph_write(void *opaque, hwaddr addr,
|
|||
(val & NV_PGRAPH_CHANNEL_CTX_POINTER_INST) << 4;
|
||||
break;
|
||||
case NV_PGRAPH_CHANNEL_CTX_TRIGGER:
|
||||
qemu_mutex_lock(&d->pgraph.lock);
|
||||
|
||||
if (val & NV_PGRAPH_CHANNEL_CTX_TRIGGER_READ_IN) {
|
||||
NV2A_DPRINTF("PGRAPH: read channel %d context from %llx\n",
|
||||
|
@ -4008,12 +4037,13 @@ static void pgraph_write(void *opaque, hwaddr addr,
|
|||
/* do stuff ... */
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&d->pgraph.lock);
|
||||
break;
|
||||
default:
|
||||
d->pgraph.regs[addr] = val;
|
||||
break;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&d->pgraph.lock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4762,13 +4792,17 @@ static int nv2a_initfn(PCIDevice *dev)
|
|||
}
|
||||
|
||||
/* init fifo cache1 */
|
||||
qemu_mutex_init(&d->pfifo.cache1.pull_lock);
|
||||
qemu_mutex_init(&d->pfifo.cache1.cache_lock);
|
||||
qemu_cond_init(&d->pfifo.cache1.cache_cond);
|
||||
QSIMPLEQ_INIT(&d->pfifo.cache1.cache);
|
||||
|
||||
pgraph_init(&d->pgraph);
|
||||
|
||||
/* fire up puller */
|
||||
qemu_thread_create(&d->pfifo.puller_thread,
|
||||
pfifo_puller_thread,
|
||||
d, QEMU_THREAD_DETACHED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4777,7 +4811,10 @@ static void nv2a_exitfn(PCIDevice *dev)
|
|||
NV2AState *d;
|
||||
d = NV2A_DEVICE(dev);
|
||||
|
||||
qemu_mutex_destroy(&d->pfifo.cache1.pull_lock);
|
||||
d->exiting = true;
|
||||
qemu_cond_signal(&d->pfifo.cache1.cache_cond);
|
||||
qemu_thread_join(&d->pfifo.puller_thread);
|
||||
|
||||
qemu_mutex_destroy(&d->pfifo.cache1.cache_lock);
|
||||
qemu_cond_destroy(&d->pfifo.cache1.cache_cond);
|
||||
|
||||
|
|
Loading…
Reference in New Issue