From 04329029a8c539eb5f75dcb6d8b016f0c53a031a Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 22 May 2015 14:13:43 -0400 Subject: ich9/ahci: Enable Migration Lift the flag preventing the migration of the ICH9/AHCI devices. Signed-off-by: John Snow Reviewed-by: Kevin Wolf Message-id: 1430417242-11859-5-git-send-email-jsnow@redhat.com --- hw/ide/ahci.c | 1 - hw/ide/ich.c | 1 - 2 files changed, 2 deletions(-) (limited to 'hw/ide') diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 833fd45faf..8e36dec5a9 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1461,7 +1461,6 @@ typedef struct SysbusAHCIState { static const VMStateDescription vmstate_sysbus_ahci = { .name = "sysbus-ahci", - .unmigratable = 1, /* Still buggy under I/O load */ .fields = (VMStateField[]) { VMSTATE_AHCI(ahci, SysbusAHCIState), VMSTATE_END_OF_LIST() diff --git a/hw/ide/ich.c b/hw/ide/ich.c index b1d8874671..350c7f1c75 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -82,7 +82,6 @@ static const VMStateDescription vmstate_ich9_ahci = { .name = "ich9_ahci", - .unmigratable = 1, /* Still buggy under I/O load */ .version_id = 1, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, AHCIPCIState), -- cgit v1.2.3 From 4827ac1e8f8306b24e61b44ea1f2082ea08099bb Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 22 May 2015 14:13:44 -0400 Subject: 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 | 253 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 147 insertions(+), 106 deletions(-) (limited to 'hw/ide') 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; -- cgit v1.2.3 From bd4214fc92090694aefa17882815c6109f0fd70c Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 22 May 2015 14:13:44 -0400 Subject: macio: move unaligned DMA write code into separate pmac_dma_write() function Similarly switch the macio IDE routines over to use the new function and tidy-up the remaining code as required. [Maintainer edit: printf format codes adjusted for 32/64bit. --js] Signed-off-by: Mark Cave-Ayland Acked-by: John Snow Message-id: 1425939893-14404-3-git-send-email-mark.cave-ayland@ilande.co.uk Signed-off-by: John Snow --- hw/ide/macio.c | 268 +++++++++++++++++++++++++++------------------------------ 1 file changed, 125 insertions(+), 143 deletions(-) (limited to 'hw/ide') 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; } } -- cgit v1.2.3 From cd6cb73beb63e5fa62ca8ed540b9d54063b15c44 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 22 May 2015 14:13:44 -0400 Subject: ahci: do not remap clb/fis unconditionally This continues the IOMMU fix from 2.3, where we should not attempt to remap the CLB or FIS RX buffers if the AHCI device is currently running. The same applies to migration: keep our mitts off these registers unless the device is supposed to be on. Does not impact backwards compatibility for the AHCI device. Signed-off-by: John Snow Reviewed-by: Stefan Hajnoczi Message-id: 1431470173-30847-2-git-send-email-jsnow@redhat.com --- hw/ide/ahci.c | 88 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 25 deletions(-) (limited to 'hw/ide') diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 8e36dec5a9..9e5d86297c 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -198,6 +198,61 @@ static void map_page(AddressSpace *as, uint8_t **ptr, uint64_t addr, } } +/** + * Check the cmd register to see if we should start or stop + * the DMA or FIS RX engines. + * + * @ad: Device to engage. + * @allow_stop: Allow device to transition from started to stopped? + * 'no' is useful for migration post_load, which does not expect a transition. + * + * @return 0 on success, -1 on error. + */ +static int ahci_cond_start_engines(AHCIDevice *ad, bool allow_stop) +{ + AHCIPortRegs *pr = &ad->port_regs; + + if (pr->cmd & PORT_CMD_START) { + if (ahci_map_clb_address(ad)) { + pr->cmd |= PORT_CMD_LIST_ON; + } else { + error_report("AHCI: Failed to start DMA engine: " + "bad command list buffer address"); + return -1; + } + } else if (pr->cmd & PORT_CMD_LIST_ON) { + if (allow_stop) { + ahci_unmap_clb_address(ad); + pr->cmd = pr->cmd & ~(PORT_CMD_LIST_ON); + } else { + error_report("AHCI: DMA engine should be off, " + "but appears to still be running"); + return -1; + } + } + + if (pr->cmd & PORT_CMD_FIS_RX) { + if (ahci_map_fis_address(ad)) { + pr->cmd |= PORT_CMD_FIS_ON; + } else { + error_report("AHCI: Failed to start FIS receive engine: " + "bad FIS receive buffer address"); + return -1; + } + } else if (pr->cmd & PORT_CMD_FIS_ON) { + if (allow_stop) { + ahci_unmap_fis_address(ad); + pr->cmd = pr->cmd & ~(PORT_CMD_FIS_ON); + } else { + error_report("AHCI: FIS receive engine should be off, " + "but appears to still be running"); + return -1; + } + } + + return 0; +} + static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) { AHCIPortRegs *pr = &s->dev[port].port_regs; @@ -229,29 +284,8 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) * including LIST_ON and FIS_ON. */ pr->cmd = (pr->cmd & PORT_CMD_RO_MASK) | (val & ~PORT_CMD_RO_MASK); - if (pr->cmd & PORT_CMD_START) { - if (ahci_map_clb_address(&s->dev[port])) { - pr->cmd |= PORT_CMD_LIST_ON; - } else { - error_report("AHCI: Failed to start DMA engine: " - "bad command list buffer address"); - } - } else if (pr->cmd & PORT_CMD_LIST_ON) { - ahci_unmap_clb_address(&s->dev[port]); - pr->cmd = pr->cmd & ~(PORT_CMD_LIST_ON); - } - - if (pr->cmd & PORT_CMD_FIS_RX) { - if (ahci_map_fis_address(&s->dev[port])) { - pr->cmd |= PORT_CMD_FIS_ON; - } else { - error_report("AHCI: Failed to start FIS receive engine: " - "bad FIS receive buffer address"); - } - } else if (pr->cmd & PORT_CMD_FIS_ON) { - ahci_unmap_fis_address(&s->dev[port]); - pr->cmd = pr->cmd & ~(PORT_CMD_FIS_ON); - } + /* Check FIS RX and CLB engines, allow transition to false: */ + ahci_cond_start_engines(&s->dev[port], true); /* XXX usually the FIS would be pending on the bus here and issuing deferred until the OS enables FIS receival. @@ -1404,8 +1438,12 @@ static int ahci_state_post_load(void *opaque, int version_id) for (i = 0; i < s->ports; i++) { ad = &s->dev[i]; - ahci_map_clb_address(ad); - ahci_map_fis_address(ad); + /* Only remap the CLB address if appropriate, disallowing a state + * transition from 'on' to 'off' it should be consistent here. */ + if (ahci_cond_start_engines(ad, false) != 0) { + return -1; + } + /* * If an error is present, ad->busy_slot will be valid and not -1. * In this case, an operation is waiting to resume and will re-check -- cgit v1.2.3