diff options
author | aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162> | 2009-03-03 09:14:10 +0000 |
---|---|---|
committer | aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162> | 2009-03-03 09:14:10 +0000 |
commit | b42ec42d4306e6da1e72a32167262343025116ed (patch) | |
tree | 7b3b21ac1051cb23416f74388cbe06ed81bdd413 /hw | |
parent | 927e3a4e066d4bce091d368b15c7ad7877a1e0e1 (diff) |
DB-DMA cleanup
Signed-off-by: Laurent Vivier <Laurent@vivier.eu>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6676 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw')
-rw-r--r-- | hw/ide.c | 88 | ||||
-rw-r--r-- | hw/mac_dbdma.c | 190 | ||||
-rw-r--r-- | hw/mac_dbdma.h | 19 |
3 files changed, 133 insertions, 164 deletions
@@ -3429,71 +3429,69 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, typedef struct MACIOIDEState { IDEState ide_if[2]; - void *dbdma; int stream_index; } MACIOIDEState; -static int pmac_atapi_read(DBDMA_transfer *info, DBDMA_transfer_cb cb) +static void pmac_atapi_read(DBDMA_io *io) { - MACIOIDEState *m = info->opaque; + MACIOIDEState *m = io->opaque; IDEState *s = m->ide_if->cur_drive; - int ret; - - if (s->lba == -1) - return 0; - - info->buf_pos = 0; + int ret, len; - while (info->buf_pos < info->len && s->packet_transfer_size > 0) { + while (io->len > 0 && + s->packet_transfer_size > 0) { - ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); + len = s->cd_sector_size; + ret = cd_read_sector(s->bs, s->lba, s->io_buffer, len); if (ret < 0) { + io->dma_end(io); ide_transfer_stop(s); ide_atapi_io_error(s, ret); - return info->buf_pos; + return; } - info->buf = s->io_buffer + m->stream_index; - - info->buf_len = s->cd_sector_size; - if (info->buf_pos + info->buf_len > info->len) - info->buf_len = info->len - info->buf_pos; + if (len > io->len) + len = io->len; - cb(info); + cpu_physical_memory_write(io->addr, + s->io_buffer + m->stream_index, len); /* db-dma can ask for 512 bytes whereas block size is 2048... */ - m->stream_index += info->buf_len; + m->stream_index += len; s->lba += m->stream_index / s->cd_sector_size; m->stream_index %= s->cd_sector_size; - info->buf_pos += info->buf_len; - s->packet_transfer_size -= info->buf_len; + io->len -= len; + io->addr += len; + s->packet_transfer_size -= len; } + + if (io->len <= 0) + io->dma_end(io); + if (s->packet_transfer_size <= 0) { s->status = READY_STAT | SEEK_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s); } - - return info->buf_pos; } -static int pmac_ide_transfer(DBDMA_transfer *info, - DBDMA_transfer_cb cb) +static void pmac_ide_transfer(DBDMA_io *io) { - MACIOIDEState *m = info->opaque; + MACIOIDEState *m = io->opaque; IDEState *s = m->ide_if->cur_drive; int64_t sector_num; int ret, n; + int len; - if (s->is_cdrom) - return pmac_atapi_read(info, cb); + if (s->is_cdrom) { + pmac_atapi_read(io); + return; + } - info->buf = s->io_buffer; - info->buf_pos = 0; - while (info->buf_pos < info->len && s->nsector > 0) { + while (io->len > 0 && s->nsector > 0) { sector_num = ide_get_sector(s); @@ -3501,36 +3499,40 @@ static int pmac_ide_transfer(DBDMA_transfer *info, if (n > IDE_DMA_BUF_SECTORS) n = IDE_DMA_BUF_SECTORS; - info->buf_len = n << 9; - if (info->buf_pos + info->buf_len > info->len) - info->buf_len = info->len - info->buf_pos; - n = info->buf_len >> 9; + len = n << 9; + if (len > io->len) + len = io->len; + n = (len + 511) >> 9; if (s->is_read) { ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); - if (ret == 0) - cb(info); + cpu_physical_memory_write(io->addr, s->io_buffer, len); } else { - cb(info); + cpu_physical_memory_read(io->addr, s->io_buffer, len); ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); } if (ret != 0) { + io->dma_end(io); ide_rw_error(s); - return info->buf_pos; + return; } - info->buf_pos += n << 9; + io->len -= len; + io->addr += len; ide_set_sector(s, sector_num + n); s->nsector -= n; } + if (io->len <= 0) + io->dma_end(io); + if (s->nsector <= 0) { s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); } - return info->buf_pos; + return; } /* PowerMac IDE memory IO */ @@ -3709,10 +3711,8 @@ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq, d = qemu_mallocz(sizeof(MACIOIDEState)); ide_init2(d->ide_if, hd_table[0], hd_table[1], irq); - if (dbdma) { - d->dbdma = dbdma; + if (dbdma) DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, d); - } pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, pmac_ide_write, d); diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index f52868e458..d6608f6893 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -158,9 +158,10 @@ typedef struct DBDMA_channel { int channel; uint32_t regs[DBDMA_REGS]; qemu_irq irq; - DBDMA_transfer io; - DBDMA_transfer_handler transfer_handler; + DBDMA_io io; + DBDMA_rw rw; dbdma_cmd current; + int processing; } DBDMA_channel; #ifdef DEBUG_DBDMA @@ -218,7 +219,7 @@ static void conditional_interrupt(DBDMA_channel *ch) DBDMA_DPRINTF("conditional_interrupt\n"); - intr = be16_to_cpu(current->command) & INTR_MASK; + intr = le16_to_cpu(current->command) & INTR_MASK; switch(intr) { case INTR_NEVER: /* don't interrupt */ @@ -257,7 +258,7 @@ static int conditional_wait(DBDMA_channel *ch) DBDMA_DPRINTF("conditional_wait\n"); - wait = be16_to_cpu(current->command) & WAIT_MASK; + wait = le16_to_cpu(current->command) & WAIT_MASK; switch(wait) { case WAIT_NEVER: /* don't wait */ @@ -318,7 +319,7 @@ static void conditional_branch(DBDMA_channel *ch) /* check if we must branch */ - br = be16_to_cpu(current->command) & BR_MASK; + br = le16_to_cpu(current->command) & BR_MASK; switch(br) { case BR_NEVER: /* don't branch */ @@ -352,38 +353,35 @@ static void conditional_branch(DBDMA_channel *ch) } } -static int dbdma_read_memory(DBDMA_transfer *io) -{ - DBDMA_channel *ch = io->channel; - dbdma_cmd *current = &ch->current; - - DBDMA_DPRINTF("DBDMA_read_memory\n"); - - cpu_physical_memory_read(le32_to_cpu(current->phy_addr) + io->buf_pos, - io->buf, io->buf_len); - - return io->buf_len; -} +static QEMUBH *dbdma_bh; +static void channel_run(DBDMA_channel *ch); -static int dbdma_write_memory(DBDMA_transfer *io) +static void dbdma_end(DBDMA_io *io) { DBDMA_channel *ch = io->channel; dbdma_cmd *current = &ch->current; - DBDMA_DPRINTF("DBDMA_write_memory\n"); + if (conditional_wait(ch)) + goto wait; - cpu_physical_memory_write(le32_to_cpu(current->phy_addr) + io->buf_pos, - io->buf, io->buf_len); + current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS])); + current->res_count = cpu_to_le16(be32_to_cpu(io->len)); + dbdma_cmdptr_save(ch); + ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH); + + conditional_interrupt(ch); + conditional_branch(ch); - return io->buf_len; +wait: + ch->processing = 0; + if ((ch->regs[DBDMA_STATUS] & cpu_to_be32(RUN)) && + (ch->regs[DBDMA_STATUS] & cpu_to_be32(ACTIVE))) + channel_run(ch); } -static int start_output(DBDMA_channel *ch, int key, uint32_t addr, +static void start_output(DBDMA_channel *ch, int key, uint32_t addr, uint16_t req_count, int is_last) { - dbdma_cmd *current = &ch->current; - uint32_t n; - DBDMA_DPRINTF("start_output\n"); /* KEY_REGS, KEY_DEVICE and KEY_STREAM @@ -393,35 +391,21 @@ static int start_output(DBDMA_channel *ch, int key, uint32_t addr, DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key); if (!addr || key > KEY_STREAM3) { kill_channel(ch); - return 0; + return; } - ch->io.buf = NULL; - ch->io.buf_pos = 0; - ch->io.buf_len = 0; + ch->io.addr = addr; ch->io.len = req_count; ch->io.is_last = is_last; - n = ch->transfer_handler(&ch->io, dbdma_read_memory); - - if (conditional_wait(ch)) - return 1; - - current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS])); - current->res_count = cpu_to_le16(0); - dbdma_cmdptr_save(ch); - - conditional_interrupt(ch); - conditional_branch(ch); - - return 1; + ch->io.dma_end = dbdma_end; + ch->io.is_dma_out = 1; + ch->processing = 1; + ch->rw(&ch->io); } -static int start_input(DBDMA_channel *ch, int key, uint32_t addr, +static void start_input(DBDMA_channel *ch, int key, uint32_t addr, uint16_t req_count, int is_last) { - dbdma_cmd *current = &ch->current; - uint32_t n; - DBDMA_DPRINTF("start_input\n"); /* KEY_REGS, KEY_DEVICE and KEY_STREAM @@ -430,30 +414,19 @@ static int start_input(DBDMA_channel *ch, int key, uint32_t addr, if (!addr || key > KEY_STREAM3) { kill_channel(ch); - return 0; + return; } - ch->io.buf = NULL; - ch->io.buf_pos = 0; - ch->io.buf_len = 0; + ch->io.addr = addr; ch->io.len = req_count; ch->io.is_last = is_last; - n = ch->transfer_handler(&ch->io, dbdma_write_memory); - - if (conditional_wait(ch)) - return 1; - - current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS])); - current->res_count = cpu_to_le16(0); - dbdma_cmdptr_save(ch); - - conditional_interrupt(ch); - conditional_branch(ch); - - return 1; + ch->io.dma_end = dbdma_end; + ch->io.is_dma_out = 0; + ch->processing = 1; + ch->rw(&ch->io); } -static int load_word(DBDMA_channel *ch, int key, uint32_t addr, +static void load_word(DBDMA_channel *ch, int key, uint32_t addr, uint16_t len) { dbdma_cmd *current = &ch->current; @@ -466,7 +439,7 @@ static int load_word(DBDMA_channel *ch, int key, uint32_t addr, if (key != KEY_SYSTEM) { printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key); kill_channel(ch); - return 0; + return; } cpu_physical_memory_read(addr, (uint8_t*)&val, len); @@ -479,18 +452,20 @@ static int load_word(DBDMA_channel *ch, int key, uint32_t addr, current->cmd_dep = val; if (conditional_wait(ch)) - return 1; + goto wait; current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS])); dbdma_cmdptr_save(ch); + ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH); conditional_interrupt(ch); next(ch); - return 1; +wait: + qemu_bh_schedule(dbdma_bh); } -static int store_word(DBDMA_channel *ch, int key, uint32_t addr, +static void store_word(DBDMA_channel *ch, int key, uint32_t addr, uint16_t len) { dbdma_cmd *current = &ch->current; @@ -503,7 +478,7 @@ static int store_word(DBDMA_channel *ch, int key, uint32_t addr, if (key != KEY_SYSTEM) { printf("DBDMA: STORE_WORD, unimplemented key %x\n", key); kill_channel(ch); - return 0; + return; } val = current->cmd_dep; @@ -515,23 +490,25 @@ static int store_word(DBDMA_channel *ch, int key, uint32_t addr, cpu_physical_memory_write(addr, (uint8_t*)&val, len); if (conditional_wait(ch)) - return 1; + goto wait; current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS])); dbdma_cmdptr_save(ch); + ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH); conditional_interrupt(ch); next(ch); - return 1; +wait: + qemu_bh_schedule(dbdma_bh); } -static int nop(DBDMA_channel *ch) +static void nop(DBDMA_channel *ch) { dbdma_cmd *current = &ch->current; if (conditional_wait(ch)) - return 1; + goto wait; current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS])); dbdma_cmdptr_save(ch); @@ -539,19 +516,18 @@ static int nop(DBDMA_channel *ch) conditional_interrupt(ch); conditional_branch(ch); - return 1; +wait: + qemu_bh_schedule(dbdma_bh); } -static int stop(DBDMA_channel *ch) +static void stop(DBDMA_channel *ch) { - ch->regs[DBDMA_STATUS] &= cpu_to_be32(~(ACTIVE|DEAD)); + ch->regs[DBDMA_STATUS] &= cpu_to_be32(~(ACTIVE|DEAD|FLUSH)); /* the stop command does not increment command pointer */ - - return 0; } -static int channel_run(DBDMA_channel *ch) +static void channel_run(DBDMA_channel *ch) { dbdma_cmd *current = &ch->current; uint16_t cmd, key; @@ -569,10 +545,12 @@ static int channel_run(DBDMA_channel *ch) switch (cmd) { case DBDMA_NOP: - return nop(ch); + nop(ch); + return; case DBDMA_STOP: - return stop(ch); + stop(ch); + return; } key = le16_to_cpu(current->command) & 0x0700; @@ -582,21 +560,25 @@ static int channel_run(DBDMA_channel *ch) if (key == KEY_STREAM4) { printf("command %x, invalid key 4\n", cmd); kill_channel(ch); - return 0; + return; } switch (cmd) { case OUTPUT_MORE: - return start_output(ch, key, phy_addr, req_count, 0); + start_output(ch, key, phy_addr, req_count, 0); + return; case OUTPUT_LAST: - return start_output(ch, key, phy_addr, req_count, 1); + start_output(ch, key, phy_addr, req_count, 1); + return; case INPUT_MORE: - return start_input(ch, key, phy_addr, req_count, 0); + start_input(ch, key, phy_addr, req_count, 0); + return; case INPUT_LAST: - return start_input(ch, key, phy_addr, req_count, 1); + start_input(ch, key, phy_addr, req_count, 1); + return; } if (key < KEY_REGS) { @@ -620,35 +602,24 @@ static int channel_run(DBDMA_channel *ch) switch (cmd) { case LOAD_WORD: - return load_word(ch, key, phy_addr, req_count); + load_word(ch, key, phy_addr, req_count); + return; case STORE_WORD: - return store_word(ch, key, phy_addr, req_count); + store_word(ch, key, phy_addr, req_count); + return; } - - return 0; } -static QEMUBH *dbdma_bh; - static void DBDMA_run (DBDMA_channel *ch) { int channel; - int rearm = 0; for (channel = 0; channel < DBDMA_CHANNELS; channel++, ch++) { uint32_t status = be32_to_cpu(ch->regs[DBDMA_STATUS]); - if ((status & RUN) && (status & ACTIVE)) { - if (status & FLUSH) - while (channel_run(ch)); - else if (channel_run(ch)) - rearm = 1; - } - ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH); + if (!ch->processing && (status & RUN) && (status & ACTIVE)) + channel_run(ch); } - - if (rearm) - qemu_bh_schedule_idle(dbdma_bh); } static void DBDMA_run_bh(void *opaque) @@ -661,7 +632,7 @@ static void DBDMA_run_bh(void *opaque) } void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, - DBDMA_transfer_handler transfer_handler, + DBDMA_rw rw, void *opaque) { DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan; @@ -670,7 +641,7 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, ch->irq = irq; ch->channel = nchan; - ch->transfer_handler = transfer_handler; + ch->rw = rw; ch->io.opaque = opaque; ch->io.channel = ch; } @@ -714,11 +685,8 @@ dbdma_control_write(DBDMA_channel *ch) ch->regs[DBDMA_STATUS] = cpu_to_be32(status); - if (status & ACTIVE) { - qemu_bh_schedule_idle(dbdma_bh); - if (status & FLUSH) - DBDMA_schedule(); - } + if (status & ACTIVE) + qemu_bh_schedule(dbdma_bh); } static void dbdma_writel (void *opaque, diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h index d1a02ed75e..35f65c340a 100644 --- a/hw/mac_dbdma.h +++ b/hw/mac_dbdma.h @@ -20,22 +20,23 @@ * THE SOFTWARE. */ -typedef struct { +typedef struct DBDMA_io DBDMA_io; + +typedef void (*DBDMA_rw)(DBDMA_io *io); +typedef void (*DBDMA_end)(DBDMA_io *io); +struct DBDMA_io { void *opaque; void *channel; + target_phys_addr_t addr; int len; int is_last; - void *buf; - int buf_pos; - int buf_len; -} DBDMA_transfer; + int is_dma_out; + DBDMA_end dma_end; +}; -typedef int (*DBDMA_transfer_cb)(DBDMA_transfer *info); -typedef int (*DBDMA_transfer_handler)(DBDMA_transfer *info, - DBDMA_transfer_cb cb); void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, - DBDMA_transfer_handler transfer_handler, + DBDMA_rw rw, void *opaque); void DBDMA_schedule(void); void* DBDMA_init (int *dbdma_mem_index); |