From 4827ac1e8f8306b24e61b44ea1f2082ea08099bb Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 22 May 2015 14:13:44 -0400 Subject: [PATCH] macio: move unaligned DMA read code into separate pmac_dma_read() function This considerably helps simplify the complexity of the macio read routines and by switching macio CDROM accesses to use the new code, fixes the issue with the CDROM device being detected intermittently by Darwin/OS X. [Maintainer edit: printf format codes adjusted for 32/64bit. --js] Signed-off-by: Mark Cave-Ayland Acked-by: John Snow Message-id: 1425939893-14404-2-git-send-email-mark.cave-ayland@ilande.co.uk Signed-off-by: John Snow --- hw/ide/macio.c | 259 ++++++++++++++++++++++++++++--------------------- 1 file changed, 150 insertions(+), 109 deletions(-) diff --git a/hw/ide/macio.c b/hw/ide/macio.c index a009674f48..037db8b1d8 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -51,18 +51,118 @@ static const int debug_macio = 0; #define MACIO_PAGE_SIZE 4096 +static void pmac_dma_read(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; + + 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("--- DMA read pop - bounce addr: %p addr: %" + HWADDR_PRIx " remainder_len: %x\n", + &io->remainder + (0x200 - transfer), io->addr, + io->remainder_len); + + cpu_physical_memory_write(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; + } + + if (io->len == 0) { + MACIO_DPRINTF("--- finished all read processing; go and finish\n"); + cb(opaque, 0); + return; + } + } + + 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 + 0x1ff) >> 9); + remainder = (nsector << 9) - io->len; + + MACIO_DPRINTF("--- DMA read transfer - addr: %" HWADDR_PRIx " len: %x\n", + io->addr, io->len); + + dma_addr = io->addr; + dma_len = io->len; + mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len, + DMA_DIRECTION_FROM_DEVICE); + + if (!remainder) { + MACIO_DPRINTF("--- DMA read aligned - addr: %" HWADDR_PRIx + " len: %x\n", io->addr, io->len); + qemu_iovec_add(&io->iov, mem, io->len); + } else { + MACIO_DPRINTF("--- DMA read unaligned - addr: %" HWADDR_PRIx + " len: %x\n", io->addr, io->len); + qemu_iovec_add(&io->iov, mem, io->len); + + MACIO_DPRINTF("--- DMA read push - bounce addr: %p " + "remainder_len: %x\n", + &io->remainder + 0x200 - remainder, remainder); + qemu_iovec_add(&io->iov, &io->remainder + 0x200 - remainder, + remainder); + + io->remainder_len = remainder; + } + + s->io_buffer_size -= io->len; + s->io_buffer_index += io->len; + + io->len = 0; + + MACIO_DPRINTF("--- Block read transfer - sector_num: %"PRIx64" " + "nsector: %x\n", + sector_num, nsector); + + m->aiocb = blk_aio_readv(blk, sector_num, &io->iov, nsector, cb, io); +} + static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) { DBDMA_io *io = opaque; MACIOIDEState *m = io->opaque; IDEState *s = idebus_active_if(&m->bus); - int unaligned; + int64_t sector_num; + int nsector, remainder; + + MACIO_DPRINTF("\ns is %p\n", s); + MACIO_DPRINTF("io_buffer_index: %x\n", s->io_buffer_index); + MACIO_DPRINTF("io_buffer_size: %x packet_transfer_size: %x\n", + s->io_buffer_size, s->packet_transfer_size); + MACIO_DPRINTF("lba: %x\n", s->lba); + MACIO_DPRINTF("io_addr: %" HWADDR_PRIx " io_len: %x\n", io->addr, + io->len); if (ret < 0) { - m->aiocb = NULL; - qemu_sglist_destroy(&s->sg); + MACIO_DPRINTF("THERE WAS AN ERROR! %d\n", ret); ide_atapi_io_error(s, ret); - io->remainder_len = 0; goto done; } @@ -74,105 +174,43 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) return; } - 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); - - s->packet_transfer_size -= s->io_buffer_size; - - s->io_buffer_index += s->io_buffer_size; - s->lba += s->io_buffer_index >> 11; - s->io_buffer_index &= 0x7ff; - } - - s->io_buffer_size = MIN(io->len, s->packet_transfer_size); - - MACIO_DPRINTF("remainder: %d io->len: %d size: %d\n", io->remainder_len, - io->len, s->packet_transfer_size); - if (io->remainder_len && io->len) { - /* guest wants the rest of its previous transfer */ - int remainder_len = MIN(io->remainder_len, io->len); - - MACIO_DPRINTF("copying remainder %d bytes\n", remainder_len); - - cpu_physical_memory_write(io->addr, io->remainder + 0x200 - - remainder_len, remainder_len); - - io->addr += remainder_len; - io->len -= remainder_len; - s->io_buffer_size = remainder_len; - io->remainder_len -= remainder_len; - /* treat remainder as individual transfer, start again */ - qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1, - &address_space_memory); - pmac_ide_atapi_transfer_cb(opaque, 0); - return; - } - - if (!s->packet_transfer_size) { - MACIO_DPRINTF("end of transfer\n"); + if (s->io_buffer_size <= 0) { ide_atapi_cmd_ok(s); m->dma_active = false; - } - - if (io->len == 0) { - MACIO_DPRINTF("end of DMA\n"); goto done; } - /* launch next transfer */ - - /* 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 sector_num = (s->lba << 2) + (s->io_buffer_index >> 9); - int nsector = io->len >> 9; - - MACIO_DPRINTF("precopying unaligned %d bytes to %#" HWADDR_PRIx "\n", - unaligned, io->addr + io->len - unaligned); - - blk_read(s->blk, sector_num + nsector, io->remainder, 1); - cpu_physical_memory_write(io->addr + io->len - unaligned, - io->remainder, unaligned); - - io->len -= unaligned; + if (io->len == 0) { + MACIO_DPRINTF("End of DMA transfer\n"); + goto done; } - 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 += s->io_buffer_size; - io->remainder_len = MIN(s->packet_transfer_size - s->io_buffer_size, - (0x200 - unaligned) & 0x1ff); - MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len); - - /* We would read no data from the block layer, thus not get a callback. - Just fake completion manually. */ - if (!io->len) { - pmac_ide_atapi_transfer_cb(opaque, 0); - return; + if (s->lba == -1) { + /* Non-block ATAPI transfer - just copy to RAM */ + s->io_buffer_size = MIN(s->io_buffer_size, io->len); + cpu_physical_memory_write(io->addr, s->io_buffer, s->io_buffer_size); + ide_atapi_cmd_ok(s); + m->dma_active = false; + goto done; } - io->len = 0; + /* Calculate number of sectors */ + sector_num = (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9); + nsector = (io->len + 0x1ff) >> 9; + remainder = io->len & 0x1ff; - MACIO_DPRINTF("sector_num=%d size=%d, cmd_cmd=%d\n", - (s->lba << 2) + (s->io_buffer_index >> 9), - s->packet_transfer_size, s->dma_cmd); + MACIO_DPRINTF("nsector: %d remainder: %x\n", nsector, remainder); + MACIO_DPRINTF("sector: %"PRIx64" %zx\n", sector_num, io->iov.size / 512); - m->aiocb = dma_blk_read(s->blk, &s->sg, - (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9), - pmac_ide_atapi_transfer_cb, io); + pmac_dma_read(s->blk, sector_num, nsector, pmac_ide_atapi_transfer_cb, io); return; done: - MACIO_DPRINTF("done DMA\n"); + MACIO_DPRINTF("done DMA\n\n"); block_acct_done(blk_get_stats(s->blk), &s->acct); io->dma_end(opaque); + + return; } static void pmac_ide_transfer_cb(void *opaque, int ret) @@ -364,33 +402,14 @@ static void pmac_ide_transfer(DBDMA_io *io) MACIO_DPRINTF("\n"); - s->io_buffer_size = 0; if (s->drive_kind == IDE_CD) { - - /* Handle non-block ATAPI DMA transfers */ - if (s->lba == -1) { - s->io_buffer_size = MIN(io->len, s->packet_transfer_size); - block_acct_start(blk_get_stats(s->blk), &s->acct, s->io_buffer_size, - BLOCK_ACCT_READ); - MACIO_DPRINTF("non-block ATAPI DMA transfer size: %d\n", - s->io_buffer_size); - - /* Copy ATAPI buffer directly to RAM and finish */ - cpu_physical_memory_write(io->addr, s->io_buffer, - s->io_buffer_size); - ide_atapi_cmd_ok(s); - m->dma_active = false; - - MACIO_DPRINTF("end of non-block ATAPI DMA transfer\n"); - block_acct_done(blk_get_stats(s->blk), &s->acct); - io->dma_end(io); - return; - } - block_acct_start(blk_get_stats(s->blk), &s->acct, io->len, BLOCK_ACCT_READ); + pmac_ide_atapi_transfer_cb(io, 0); return; + } else { + s->io_buffer_size = 0; } switch (s->dma_cmd) { @@ -562,6 +581,28 @@ static void ide_dbdma_start(IDEDMA *dma, IDEState *s, BlockCompletionFunc *cb) { MACIOIDEState *m = container_of(dma, MACIOIDEState, dma); + DBDMAState *dbdma = m->dbdma; + DBDMA_io *io; + int i; + + if (s->drive_kind == IDE_CD) { + s->io_buffer_index = 0; + s->io_buffer_size = s->packet_transfer_size; + + 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; + + if (io->opaque == m) { + io->remainder_len = 0; + } + } + } MACIO_DPRINTF("\n"); m->dma_active = true;