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>
This commit is contained in:
parent
5560b85a31
commit
4827ac1e8f
259
hw/ide/macio.c
259
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;
|
||||
|
Loading…
Reference in New Issue
Block a user