aboutsummaryrefslogtreecommitdiff
path: root/hw/ide
diff options
context:
space:
mode:
authorMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2015-05-22 14:13:44 -0400
committerJohn Snow <jsnow@redhat.com>2015-05-22 15:58:22 -0400
commit4827ac1e8f8306b24e61b44ea1f2082ea08099bb (patch)
treeb3ace574d31942e5e911cfc5b42d5f6f075a5484 /hw/ide
parent5560b85a31e6f15a8841b66620d9497943094ee4 (diff)
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 <mark.cave-ayland@ailande.co.uk> Acked-by: John Snow <jsnow@redhat.com> Message-id: 1425939893-14404-2-git-send-email-mark.cave-ayland@ilande.co.uk Signed-off-by: John Snow <jsnow@redhat.com>
Diffstat (limited to 'hw/ide')
-rw-r--r--hw/ide/macio.c253
1 files changed, 147 insertions, 106 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,128 +51,166 @@ static const int debug_macio = 0;
#define MACIO_PAGE_SIZE 4096
-static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
+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);
- int unaligned;
+ dma_addr_t dma_addr, dma_len;
+ void *mem;
+ int nsector, remainder;
- if (ret < 0) {
- m->aiocb = NULL;
- qemu_sglist_destroy(&s->sg);
- ide_atapi_io_error(s, ret);
- io->remainder_len = 0;
- goto done;
+ 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 (!m->dma_active) {
- MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
- s->nsector, io->len, s->status);
- /* data not ready yet, wait for the channel to get restarted */
- io->processing = false;
- 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);
}
- MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size);
+ nsector = ((io->len + 0x1ff) >> 9);
+ remainder = (nsector << 9) - io->len;
- if (s->io_buffer_size > 0) {
- m->aiocb = NULL;
- qemu_sglist_destroy(&s->sg);
+ 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);
- s->packet_transfer_size -= s->io_buffer_size;
+ 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);
- s->io_buffer_index += s->io_buffer_size;
- s->lba += s->io_buffer_index >> 11;
- s->io_buffer_index &= 0x7ff;
+ io->remainder_len = remainder;
}
- s->io_buffer_size = MIN(io->len, s->packet_transfer_size);
+ s->io_buffer_size -= io->len;
+ s->io_buffer_index += io->len;
- 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);
+ io->len = 0;
- MACIO_DPRINTF("copying remainder %d bytes\n", remainder_len);
+ MACIO_DPRINTF("--- Block read transfer - sector_num: %"PRIx64" "
+ "nsector: %x\n",
+ sector_num, nsector);
- cpu_physical_memory_write(io->addr, io->remainder + 0x200 -
- remainder_len, remainder_len);
+ m->aiocb = blk_aio_readv(blk, sector_num, &io->iov, nsector, cb, io);
+}
- 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);
+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);
+ 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) {
+ MACIO_DPRINTF("THERE WAS AN ERROR! %d\n", ret);
+ ide_atapi_io_error(s, ret);
+ goto done;
+ }
+
+ if (!m->dma_active) {
+ MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
+ s->nsector, io->len, s->status);
+ /* data not ready yet, wait for the channel to get restarted */
+ io->processing = false;
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;
+ goto done;
}
if (io->len == 0) {
- MACIO_DPRINTF("end of DMA\n");
+ MACIO_DPRINTF("End of DMA transfer\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;
- }
-
- 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;