From 14eefd0ec3b4720faddf4cc7682d7ac8c82a3a45 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 24 Jun 2013 21:40:50 +0200 Subject: PPC: g3beige: Move secondary IDE bus to mac-io On a real G3 Beige the secondary IDE bus lives on the mac-io chip, not on some random PCI device. Move it there to become more compatible. While at it, also clean up the IDE channel connection logic. Signed-off-by: Alexander Graf --- hw/ide/macio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/ide/macio.c') diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 479820239e..0b05a74e45 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -363,7 +363,7 @@ static void macio_ide_register_types(void) type_register_static(&macio_ide_type_info); } -/* hd_table must contain 4 block drivers */ +/* hd_table must contain 2 block drivers */ void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table) { int i; -- cgit 1.4.1 From 8aef291fb876670b264297ab333f5072cddbf625 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 30 Jun 2013 01:43:17 +0200 Subject: PPC: Macio: Replace tabs with spaces s/^I/ /g on the file. Signed-off-by: Alexander Graf --- hw/ide/macio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'hw/ide/macio.c') diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 0b05a74e45..60b64ac22b 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -55,7 +55,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) s->packet_transfer_size -= s->io_buffer_size; s->io_buffer_index += s->io_buffer_size; - s->lba += s->io_buffer_index >> 11; + s->lba += s->io_buffer_index >> 11; s->io_buffer_index &= 0x7ff; } @@ -97,7 +97,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) if (ret < 0) { m->aiocb = NULL; qemu_sglist_destroy(&s->sg); - ide_dma_error(s); + ide_dma_error(s); goto done; } @@ -136,11 +136,11 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) switch (s->dma_cmd) { case IDE_DMA_READ: m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, - pmac_ide_transfer_cb, io); + pmac_ide_transfer_cb, io); break; case IDE_DMA_WRITE: m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, - pmac_ide_transfer_cb, io); + pmac_ide_transfer_cb, io); break; case IDE_DMA_TRIM: m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num, -- cgit 1.4.1 From 33ce36bb33cc00ac3070d49e17b4afed62b412a8 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 30 Jun 2013 01:23:45 +0200 Subject: PPC: Mac: Add debug prints in macio and dbdma code The macio code is basically undebuggable as it stands today, with no debug prints anywhere whatsoever. DBDMA was better, but I needed a few more to create reasonable logs that tell me where breakage is. Add a DPRINTF macro in the macio source file and add a bunch of debug prints that are all disabled by default of course. Signed-off-by: Alexander Graf --- hw/ide/macio.c | 43 ++++++++++++++++++++++++++++++++++++++++--- hw/misc/macio/mac_dbdma.c | 14 +++++++++++--- 2 files changed, 51 insertions(+), 6 deletions(-) (limited to 'hw/ide/macio.c') diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 60b64ac22b..8d42b5c2bb 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -30,6 +30,22 @@ #include +/* debug MACIO */ +// #define DEBUG_MACIO + +#ifdef DEBUG_MACIO +static const int debug_macio = 1; +#else +static const int debug_macio = 0; +#endif + +#define MACIO_DPRINTF(fmt, ...) do { \ + if (debug_macio) { \ + printf(fmt , ## __VA_ARGS__); \ + } \ + } while (0) + + /***********************************************************/ /* MacIO based PowerPC IDE */ @@ -48,6 +64,8 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) goto done; } + 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); @@ -59,15 +77,20 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) s->io_buffer_index &= 0x7ff; } - if (s->packet_transfer_size <= 0) + if (s->packet_transfer_size <= 0) { + MACIO_DPRINTF("end of transfer\n"); ide_atapi_cmd_ok(s); + } if (io->len == 0) { + MACIO_DPRINTF("end of DMA\n"); goto done; } /* launch next transfer */ + MACIO_DPRINTF("io->len = %#x\n", io->len); + s->io_buffer_size = io->len; qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1, @@ -76,12 +99,17 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) io->addr += io->len; io->len = 0; + 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); + m->aiocb = dma_bdrv_read(s->bs, &s->sg, (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9), pmac_ide_atapi_transfer_cb, io); return; done: + MACIO_DPRINTF("done DMA\n"); bdrv_acct_done(s->bs, &s->acct); io->dma_end(opaque); } @@ -95,6 +123,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) int64_t sector_num; if (ret < 0) { + MACIO_DPRINTF("DMA error\n"); m->aiocb = NULL; qemu_sglist_destroy(&s->sg); ide_dma_error(s); @@ -102,6 +131,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) } 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); @@ -111,14 +141,14 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) s->nsector -= n; } - /* end of transfer ? */ if (s->nsector == 0) { + MACIO_DPRINTF("end of transfer\n"); s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); } - /* end of DMA ? */ if (io->len == 0) { + MACIO_DPRINTF("end of DMA\n"); goto done; } @@ -127,12 +157,17 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) s->io_buffer_index = 0; s->io_buffer_size = io->len; + 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; io->len = 0; + MACIO_DPRINTF("sector_num=%" PRId64 " n=%d, nsector=%d, cmd_cmd=%d\n", + sector_num, n, s->nsector, s->dma_cmd); + switch (s->dma_cmd) { case IDE_DMA_READ: m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, @@ -162,6 +197,8 @@ static void pmac_ide_transfer(DBDMA_io *io) MACIOIDEState *m = io->opaque; IDEState *s = idebus_active_if(&m->bus); + MACIO_DPRINTF("\n"); + s->io_buffer_size = 0; if (s->drive_kind == IDE_CD) { bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ); diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c index fc46727762..0d7f40bf32 100644 --- a/hw/misc/macio/mac_dbdma.c +++ b/hw/misc/macio/mac_dbdma.c @@ -224,7 +224,7 @@ static void conditional_interrupt(DBDMA_channel *ch) uint32_t status; int cond; - DBDMA_DPRINTF("conditional_interrupt\n"); + DBDMA_DPRINTF("%s\n", __func__); intr = le16_to_cpu(current->command) & INTR_MASK; @@ -233,6 +233,7 @@ static void conditional_interrupt(DBDMA_channel *ch) return; case INTR_ALWAYS: /* always interrupt */ qemu_irq_raise(ch->irq); + DBDMA_DPRINTF("%s: raise\n", __func__); return; } @@ -245,12 +246,16 @@ static void conditional_interrupt(DBDMA_channel *ch) switch(intr) { case INTR_IFSET: /* intr if condition bit is 1 */ - if (cond) + if (cond) { qemu_irq_raise(ch->irq); + DBDMA_DPRINTF("%s: raise\n", __func__); + } return; case INTR_IFCLR: /* intr if condition bit is 0 */ - if (!cond) + if (!cond) { qemu_irq_raise(ch->irq); + DBDMA_DPRINTF("%s: raise\n", __func__); + } return; } } @@ -368,6 +373,8 @@ static void dbdma_end(DBDMA_io *io) DBDMA_channel *ch = io->channel; dbdma_cmd *current = &ch->current; + DBDMA_DPRINTF("%s\n", __func__); + if (conditional_wait(ch)) goto wait; @@ -422,6 +429,7 @@ static void start_input(DBDMA_channel *ch, int key, uint32_t addr, * are not implemented in the mac-io chip */ + DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key); if (!addr || key > KEY_STREAM3) { kill_channel(ch); return; -- cgit 1.4.1 From 4aa3510f6f36c5ea35219acf641788222d977437 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 30 Jun 2013 02:36:14 +0200 Subject: PPC: dbdma: macio: Add DMA callback We need to know when the IDE core starts a DMA transfer. Add a notifier function so we have the chance to start transmitting data. Signed-off-by: Alexander Graf --- hw/ide/macio.c | 40 ++++++++++++++++++++++++++++++++++++++++ hw/ppc/mac.h | 2 ++ 2 files changed, 42 insertions(+) (limited to 'hw/ide/macio.c') diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 8d42b5c2bb..126549dcdc 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -359,11 +359,50 @@ static void macio_ide_reset(DeviceState *dev) ide_bus_reset(&d->bus); } +static int ide_nop(IDEDMA *dma) +{ + return 0; +} + +static int ide_nop_int(IDEDMA *dma, int x) +{ + return 0; +} + +static void ide_nop_restart(void *opaque, int x, RunState y) +{ +} + +static void ide_dbdma_start(IDEDMA *dma, IDEState *s, + BlockDriverCompletionFunc *cb) +{ + MACIOIDEState *m = container_of(dma, MACIOIDEState, dma); + + MACIO_DPRINTF("\n"); + DBDMA_kick(m->dbdma); +} + +static const IDEDMAOps dbdma_ops = { + .start_dma = ide_dbdma_start, + .start_transfer = ide_nop, + .prepare_buf = ide_nop_int, + .rw_buf = ide_nop_int, + .set_unit = ide_nop_int, + .add_status = ide_nop_int, + .set_inactive = ide_nop, + .restart_cb = ide_nop_restart, + .reset = ide_nop, +}; + static void macio_ide_realizefn(DeviceState *dev, Error **errp) { MACIOIDEState *s = MACIO_IDE(dev); ide_init2(&s->bus, s->irq); + + /* Register DMA callbacks */ + s->dma.ops = &dbdma_ops; + s->bus.dma = &s->dma; } static void macio_ide_initfn(Object *obj) @@ -414,6 +453,7 @@ void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table) void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel) { + s->dbdma = dbdma; DBDMA_register_channel(dbdma, channel, s->dma_irq, pmac_ide_transfer, pmac_ide_flush, s); } diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 54efaed627..27c4ca39be 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -131,6 +131,8 @@ typedef struct MACIOIDEState { MemoryRegion mem; IDEBus bus; BlockDriverAIOCB *aiocb; + IDEDMA dma; + void *dbdma; } MACIOIDEState; void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table); -- cgit 1.4.1 From cae323572eddc1a45e2f6ef98c006d98fed23b1e Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 30 Jun 2013 02:54:35 +0200 Subject: PPC: dbdma: Wait for DMA until we have data We should only start processing DMA requests when we have data to process. Hold off working through the DMA shuffling until the IDE core told us that it's ready. This is required because the guest can program the DMA engine or the IDE transfer first. Both are legal. Signed-off-by: Alexander Graf --- hw/ide/macio.c | 19 +++++++++++++++++++ hw/ppc/mac.h | 1 + 2 files changed, 20 insertions(+) (limited to 'hw/ide/macio.c') diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 126549dcdc..2b1e51d49e 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -64,6 +64,14 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int 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; + } + MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size); if (s->io_buffer_size > 0) { @@ -80,6 +88,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) if (s->packet_transfer_size <= 0) { MACIO_DPRINTF("end of transfer\n"); ide_atapi_cmd_ok(s); + m->dma_active = false; } if (io->len == 0) { @@ -130,6 +139,14 @@ static void pmac_ide_transfer_cb(void *opaque, int 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; + } + sector_num = ide_get_sector(s); MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size); if (s->io_buffer_size > 0) { @@ -145,6 +162,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) MACIO_DPRINTF("end of transfer\n"); s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); + m->dma_active = false; } if (io->len == 0) { @@ -379,6 +397,7 @@ static void ide_dbdma_start(IDEDMA *dma, IDEState *s, MACIOIDEState *m = container_of(dma, MACIOIDEState, dma); MACIO_DPRINTF("\n"); + m->dma_active = true; DBDMA_kick(m->dbdma); } diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 27c4ca39be..1e578dd59d 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -133,6 +133,7 @@ typedef struct MACIOIDEState { BlockDriverAIOCB *aiocb; IDEDMA dma; void *dbdma; + bool dma_active; } MACIOIDEState; void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table); -- cgit 1.4.1 From 80fc95d8bdaf3392106b131a97ca701fd374489a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 28 Jun 2013 13:30:01 +0200 Subject: PPC: dbdma: Support unaligned DMA access The DBDMA engine really just reads bytes from a producing device (IDE in our case) and shoves these bytes into memory. It doesn't care whether any alignment takes place or not. Our code today however assumes that block accesses always happen on sector (512 byte) boundaries. This is a fair assumption for most cases. However, Mac OS X really likes to do unaligned, incomplete accesses that it finishes with the next DMA request. So we need to read / write the unaligned bits independent of the actual asynchronous request, because that one can only handle 512-byte-aligned data. We also need to cache these unaligned sectors until the next DMA request, at which point the data might be successfully flushed from the pipe. Signed-off-by: Alexander Graf --- hw/ide/macio.c | 131 ++++++++++++++++++++++++++++++++++++++++++--- include/hw/ppc/mac_dbdma.h | 3 ++ 2 files changed, 127 insertions(+), 7 deletions(-) (limited to 'hw/ide/macio.c') diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 2b1e51d49e..18bc1d1273 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -56,11 +56,13 @@ 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; if (ret < 0) { m->aiocb = NULL; qemu_sglist_destroy(&s->sg); ide_atapi_io_error(s, ret); + io->remainder_len = 0; goto done; } @@ -85,7 +87,31 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) s->io_buffer_index &= 0x7ff; } - if (s->packet_transfer_size <= 0) { + s->io_buffer_size = 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); + + 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"); ide_atapi_cmd_ok(s); m->dma_active = false; @@ -98,14 +124,40 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) /* launch next transfer */ - MACIO_DPRINTF("io->len = %#x\n", io->len); + /* 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; - s->io_buffer_size = io->len; + MACIO_DPRINTF("precopying unaligned %d bytes to %#lx\n", + unaligned, io->addr + io->len - unaligned); + + bdrv_read(s->bs, 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 += 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; + } + io->len = 0; MACIO_DPRINTF("sector_num=%d size=%d, cmd_cmd=%d\n", @@ -128,14 +180,16 @@ 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; + int n = 0; int64_t sector_num; + int unaligned; 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; } @@ -158,7 +212,33 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) s->nsector -= n; } - if (s->nsector == 0) { + MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d sector_num: %ld\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 %#lx\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); + bdrv_write(s->bs, sector_num - 1, io->remainder, 1); + break; + case IDE_DMA_TRIM: + break; + } + io->addr += remainder_len; + io->len -= remainder_len; + io->remainder_len -= remainder_len; + } + + if (s->nsector == 0 && !io->remainder_len) { MACIO_DPRINTF("end of transfer\n"); s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); @@ -175,12 +255,49 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) s->io_buffer_index = 0; s->io_buffer_size = io->len; + /* 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 %#lx\n", + unaligned, io->addr + io->len - unaligned); + + switch (s->dma_cmd) { + case IDE_DMA_READ: + bdrv_read(s->bs, sector_num + nsector, io->remainder, 1); + cpu_physical_memory_write(io->addr + io->len - unaligned, + io->remainder, unaligned); + break; + case IDE_DMA_WRITE: + /* cache the contents in our io struct */ + cpu_physical_memory_read(io->addr + io->len - unaligned, + io->remainder, unaligned); + break; + case IDE_DMA_TRIM: + break; + } + + 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 += io->len; + io->addr += io->len + unaligned; + io->remainder_len = (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_transfer_cb(opaque, 0); + return; + } + io->len = 0; MACIO_DPRINTF("sector_num=%" PRId64 " n=%d, nsector=%d, cmd_cmd=%d\n", diff --git a/include/hw/ppc/mac_dbdma.h b/include/hw/ppc/mac_dbdma.h index 4d7318df84..90efd277e4 100644 --- a/include/hw/ppc/mac_dbdma.h +++ b/include/hw/ppc/mac_dbdma.h @@ -39,6 +39,9 @@ struct DBDMA_io { DBDMA_end dma_end; /* DMA is in progress, don't start another one */ bool processing; + /* unaligned last sector of a request */ + uint8_t remainder[0x200]; + int remainder_len; }; /* -- cgit 1.4.1 From f35ea98cd9f75db9286f05bf3dc4b532f4cb5eaa Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 30 Jun 2013 15:29:13 +0200 Subject: PPC: dbdma: Support more multi-issue DMA requests A DMA request can happen for data that hasn't been completely been provided by the IDE core yet. For example - DBDMA request for 0x1000 bytes - IDE request for 1 sector - DBDMA wants to read 0x1000 bytes (8 sectors) from bdrv - breakage Instead, we should truncate our bdrv request to the maximum number of sectors we're allowed to read at that given time. Once that transfer is through, we will fall into our recently introduced waiting logic. - DBDMA requests for 0x1000 bytes - IDE request for 1 sector - DBDMA wants to read MIN(0x1000, 1 * 512) bytes - DBDMA finishes reading, indicates to IDE core that transfer is complete - IDE request for 7 sectors - DBDMA finishes the DMA Reported-by: Mark Cave-Ayland Signed-off-by: Alexander Graf --- hw/ide/macio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw/ide/macio.c') diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 18bc1d1273..38ad92423d 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -87,7 +87,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) s->io_buffer_index &= 0x7ff; } - s->io_buffer_size = io->len; + 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); @@ -253,7 +253,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) /* launch next transfer */ s->io_buffer_index = 0; - s->io_buffer_size = io->len; + 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 */ -- cgit 1.4.1