diff options
-rw-r--r-- | hw/ide/macio.c | 268 | ||||
-rw-r--r-- | include/hw/ppc/mac_dbdma.h | 4 |
2 files changed, 125 insertions, 147 deletions
diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 037db8b1d8..585a27bd6c 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -144,6 +144,101 @@ static void pmac_dma_read(BlockBackend *blk, m->aiocb = blk_aio_readv(blk, sector_num, &io->iov, nsector, cb, io); } +static void pmac_dma_write(BlockBackend *blk, + int64_t sector_num, int nb_sectors, + void (*cb)(void *opaque, int ret), void *opaque) +{ + DBDMA_io *io = opaque; + MACIOIDEState *m = io->opaque; + IDEState *s = idebus_active_if(&m->bus); + dma_addr_t dma_addr, dma_len; + void *mem; + int nsector, remainder; + int extra = 0; + + qemu_iovec_destroy(&io->iov); + qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1); + + if (io->remainder_len > 0) { + /* Return remainder of request */ + int transfer = MIN(io->remainder_len, io->len); + + MACIO_DPRINTF("--- processing write remainder %x\n", transfer); + cpu_physical_memory_read(io->addr, + &io->remainder + (0x200 - transfer), + transfer); + + io->remainder_len -= transfer; + io->len -= transfer; + io->addr += transfer; + + s->io_buffer_index += transfer; + s->io_buffer_size -= transfer; + + if (io->remainder_len != 0) { + /* Still waiting for remainder */ + return; + } + + MACIO_DPRINTF("--> prepending bounce buffer with size 0x200\n"); + + /* Sector transfer complete - prepend to request */ + qemu_iovec_add(&io->iov, &io->remainder, 0x200); + extra = 1; + } + + if (s->drive_kind == IDE_CD) { + sector_num = (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9); + } else { + sector_num = ide_get_sector(s) + (s->io_buffer_index >> 9); + } + + nsector = (io->len >> 9); + remainder = io->len - (nsector << 9); + + MACIO_DPRINTF("--- DMA write transfer - addr: %" HWADDR_PRIx " len: %x\n", + io->addr, io->len); + MACIO_DPRINTF("xxx remainder: %x\n", remainder); + MACIO_DPRINTF("xxx sector_num: %"PRIx64" nsector: %x\n", + sector_num, nsector); + + dma_addr = io->addr; + dma_len = io->len; + mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len, + DMA_DIRECTION_TO_DEVICE); + + if (!remainder) { + MACIO_DPRINTF("--- DMA write aligned - addr: %" HWADDR_PRIx + " len: %x\n", io->addr, io->len); + qemu_iovec_add(&io->iov, mem, io->len); + } else { + /* Write up to last complete sector */ + MACIO_DPRINTF("--- DMA write unaligned - addr: %" HWADDR_PRIx + " len: %x\n", io->addr, (nsector << 9)); + qemu_iovec_add(&io->iov, mem, (nsector << 9)); + + MACIO_DPRINTF("--- DMA write read - bounce addr: %p " + "remainder_len: %x\n", &io->remainder, remainder); + cpu_physical_memory_read(io->addr + (nsector << 9), &io->remainder, + remainder); + + io->remainder_len = 0x200 - remainder; + + MACIO_DPRINTF("xxx remainder_len: %x\n", io->remainder_len); + } + + s->io_buffer_size -= ((nsector + extra) << 9); + s->io_buffer_index += ((nsector + extra) << 9); + + io->len = 0; + + MACIO_DPRINTF("--- Block write transfer - sector_num: %"PRIx64" " + "nsector: %x\n", sector_num, nsector + extra); + + m->aiocb = blk_aio_writev(blk, sector_num, &io->iov, nsector + extra, cb, + io); +} + static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) { DBDMA_io *io = opaque; @@ -218,24 +313,19 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) DBDMA_io *io = opaque; MACIOIDEState *m = io->opaque; IDEState *s = idebus_active_if(&m->bus); - int n = 0; int64_t sector_num; - int unaligned; + int nsector, remainder; + + MACIO_DPRINTF("pmac_ide_transfer_cb\n"); if (ret < 0) { MACIO_DPRINTF("DMA error\n"); m->aiocb = NULL; - qemu_sglist_destroy(&s->sg); ide_dma_error(s); io->remainder_len = 0; goto done; } - if (--io->requests) { - /* More requests still in flight */ - return; - } - if (!m->dma_active) { MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n", s->nsector, io->len, s->status); @@ -244,155 +334,48 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) return; } - sector_num = ide_get_sector(s); - MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size); - if (s->io_buffer_size > 0) { - m->aiocb = NULL; - qemu_sglist_destroy(&s->sg); - n = (s->io_buffer_size + 0x1ff) >> 9; - sector_num += n; - ide_set_sector(s, sector_num); - s->nsector -= n; - } - - if (io->finish_remain_read) { - /* Finish a stale read from the last iteration */ - io->finish_remain_read = false; - cpu_physical_memory_write(io->finish_addr, io->remainder, - io->finish_len); - } - - MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d " - "sector_num: %" PRId64 "\n", - io->remainder_len, io->len, s->nsector, sector_num); - if (io->remainder_len && io->len) { - /* guest wants the rest of its previous transfer */ - int remainder_len = MIN(io->remainder_len, io->len); - uint8_t *p = &io->remainder[0x200 - remainder_len]; - - MACIO_DPRINTF("copying remainder %d bytes at %#" HWADDR_PRIx "\n", - remainder_len, io->addr); - - switch (s->dma_cmd) { - case IDE_DMA_READ: - cpu_physical_memory_write(io->addr, p, remainder_len); - break; - case IDE_DMA_WRITE: - cpu_physical_memory_read(io->addr, p, remainder_len); - break; - case IDE_DMA_TRIM: - break; - } - io->addr += remainder_len; - io->len -= remainder_len; - io->remainder_len -= remainder_len; - - if (s->dma_cmd == IDE_DMA_WRITE && !io->remainder_len) { - io->requests++; - qemu_iovec_reset(&io->iov); - qemu_iovec_add(&io->iov, io->remainder, 0x200); - - m->aiocb = blk_aio_writev(s->blk, sector_num - 1, &io->iov, 1, - pmac_ide_transfer_cb, io); - } - } - - if (s->nsector == 0 && !io->remainder_len) { + if (s->io_buffer_size <= 0) { MACIO_DPRINTF("end of transfer\n"); s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); m->dma_active = false; + goto done; } if (io->len == 0) { - MACIO_DPRINTF("end of DMA\n"); + MACIO_DPRINTF("End of DMA transfer\n"); goto done; } - /* launch next transfer */ - - s->io_buffer_index = 0; - s->io_buffer_size = MIN(io->len, s->nsector * 512); - - /* handle unaligned accesses first, get them over with and only do the - remaining bulk transfer using our async DMA helpers */ - unaligned = io->len & 0x1ff; - if (unaligned) { - int nsector = io->len >> 9; - - MACIO_DPRINTF("precopying unaligned %d bytes to %#" HWADDR_PRIx "\n", - unaligned, io->addr + io->len - unaligned); - - switch (s->dma_cmd) { - case IDE_DMA_READ: - io->requests++; - io->finish_addr = io->addr + io->len - unaligned; - io->finish_len = unaligned; - io->finish_remain_read = true; - qemu_iovec_reset(&io->iov); - qemu_iovec_add(&io->iov, io->remainder, 0x200); - - m->aiocb = blk_aio_readv(s->blk, sector_num + nsector, &io->iov, 1, - pmac_ide_transfer_cb, io); - break; - case IDE_DMA_WRITE: - /* cache the contents in our io struct */ - cpu_physical_memory_read(io->addr + io->len - unaligned, - io->remainder + io->remainder_len, - unaligned); - break; - case IDE_DMA_TRIM: - break; - } - } - - MACIO_DPRINTF("io->len = %#x\n", io->len); - - qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1, - &address_space_memory); - qemu_sglist_add(&s->sg, io->addr, io->len); - io->addr += io->len + unaligned; - io->remainder_len = (0x200 - unaligned) & 0x1ff; - MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len); - - /* Only subsector reads happening */ - if (!io->len) { - if (!io->requests) { - io->requests++; - pmac_ide_transfer_cb(opaque, ret); - } - return; - } + /* Calculate number of sectors */ + sector_num = ide_get_sector(s) + (s->io_buffer_index >> 9); + nsector = (io->len + 0x1ff) >> 9; + remainder = io->len & 0x1ff; - io->len = 0; + s->nsector -= nsector; - MACIO_DPRINTF("sector_num=%" PRId64 " n=%d, nsector=%d, cmd_cmd=%d\n", - sector_num, n, s->nsector, s->dma_cmd); + MACIO_DPRINTF("nsector: %d remainder: %x\n", nsector, remainder); + MACIO_DPRINTF("sector: %"PRIx64" %x\n", sector_num, nsector); switch (s->dma_cmd) { case IDE_DMA_READ: - m->aiocb = dma_blk_read(s->blk, &s->sg, sector_num, - pmac_ide_transfer_cb, io); + pmac_dma_read(s->blk, sector_num, nsector, pmac_ide_transfer_cb, io); break; case IDE_DMA_WRITE: - m->aiocb = dma_blk_write(s->blk, &s->sg, sector_num, - pmac_ide_transfer_cb, io); + pmac_dma_write(s->blk, sector_num, nsector, pmac_ide_transfer_cb, io); break; case IDE_DMA_TRIM: - m->aiocb = dma_blk_io(s->blk, &s->sg, sector_num, - ide_issue_trim, pmac_ide_transfer_cb, io, - DMA_DIRECTION_TO_DEVICE); + MACIO_DPRINTF("TRIM command issued!"); break; } - io->requests++; return; done: if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) { block_acct_done(blk_get_stats(s->blk), &s->acct); } - io->dma_end(io); + io->dma_end(opaque); } static void pmac_ide_transfer(DBDMA_io *io) @@ -408,8 +391,6 @@ static void pmac_ide_transfer(DBDMA_io *io) pmac_ide_atapi_transfer_cb(io, 0); return; - } else { - s->io_buffer_size = 0; } switch (s->dma_cmd) { @@ -425,7 +406,6 @@ static void pmac_ide_transfer(DBDMA_io *io) break; } - io->requests++; pmac_ide_transfer_cb(io, 0); } @@ -585,22 +565,24 @@ static void ide_dbdma_start(IDEDMA *dma, IDEState *s, DBDMA_io *io; int i; + s->io_buffer_index = 0; if (s->drive_kind == IDE_CD) { - s->io_buffer_index = 0; s->io_buffer_size = s->packet_transfer_size; + } else { + s->io_buffer_size = s->nsector * 0x200; + } - MACIO_DPRINTF("\n\n------------ IDE transfer\n"); - MACIO_DPRINTF("buffer_size: %x buffer_index: %x\n", - s->io_buffer_size, s->io_buffer_index); - MACIO_DPRINTF("lba: %x size: %x\n", s->lba, s->io_buffer_size); - MACIO_DPRINTF("-------------------------\n"); + MACIO_DPRINTF("\n\n------------ IDE transfer\n"); + MACIO_DPRINTF("buffer_size: %x buffer_index: %x\n", + s->io_buffer_size, s->io_buffer_index); + MACIO_DPRINTF("lba: %x size: %x\n", s->lba, s->io_buffer_size); + MACIO_DPRINTF("-------------------------\n"); - for (i = 0; i < DBDMA_CHANNELS; i++) { - io = &dbdma->channels[i].io; + for (i = 0; i < DBDMA_CHANNELS; i++) { + io = &dbdma->channels[i].io; - if (io->opaque == m) { - io->remainder_len = 0; - } + if (io->opaque == m) { + io->remainder_len = 0; } } diff --git a/include/hw/ppc/mac_dbdma.h b/include/hw/ppc/mac_dbdma.h index d7db06c031..c5803279da 100644 --- a/include/hw/ppc/mac_dbdma.h +++ b/include/hw/ppc/mac_dbdma.h @@ -43,10 +43,6 @@ struct DBDMA_io { uint8_t remainder[0x200]; int remainder_len; QEMUIOVector iov; - bool finish_remain_read; - hwaddr finish_addr; - hwaddr finish_len; - int requests; }; /* |