diff options
author | aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162> | 2009-03-04 07:20:40 +0000 |
---|---|---|
committer | aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162> | 2009-03-04 07:20:40 +0000 |
commit | 862c928064cf0f079d81b24db932a093e49d101d (patch) | |
tree | 71e0ba8dcf6f5e89b947567c103b6935d55b2e15 | |
parent | 3c4cf5353b25d62795ecafbc88ea67e3ede4196f (diff) |
DB-DMA IDE asynchronous I/O
Signed-off-by: Laurent Vivier <Laurent@vivier.eu>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6681 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | hw/ide.c | 173 | ||||
-rw-r--r-- | hw/mac_dbdma.c | 9 | ||||
-rw-r--r-- | hw/mac_dbdma.h | 3 |
3 files changed, 112 insertions, 73 deletions
@@ -3429,110 +3429,143 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, typedef struct MACIOIDEState { IDEState ide_if[2]; - int stream_index; + BlockDriverAIOCB *aiocb; } MACIOIDEState; -static void pmac_atapi_read(DBDMA_io *io) +static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) { + DBDMA_io *io = opaque; MACIOIDEState *m = io->opaque; IDEState *s = m->ide_if->cur_drive; - int ret, len; - - while (io->len > 0 && - s->packet_transfer_size > 0) { - len = s->cd_sector_size; - ret = cd_read_sector(s->bs, s->lba, s->io_buffer, len); - if (ret < 0) { - io->dma_end(io); - ide_transfer_stop(s); - ide_atapi_io_error(s, ret); - return; - } + if (ret < 0) { + m->aiocb = NULL; + qemu_sglist_destroy(&s->sg); + ide_atapi_io_error(s, ret); + io->dma_end(opaque); + return; + } - if (len > io->len) - len = io->len; + if (s->io_buffer_size > 0) { + m->aiocb = NULL; + qemu_sglist_destroy(&s->sg); - cpu_physical_memory_write(io->addr, - s->io_buffer + m->stream_index, len); + s->packet_transfer_size -= s->io_buffer_size; - /* db-dma can ask for 512 bytes whereas block size is 2048... */ + s->io_buffer_index += s->io_buffer_size; + s->lba += s->io_buffer_index >> 11; + s->io_buffer_index &= 0x7ff; + } - m->stream_index += len; - s->lba += m->stream_index / s->cd_sector_size; - m->stream_index %= s->cd_sector_size; + if (s->packet_transfer_size <= 0) + ide_atapi_cmd_ok(s); - io->len -= len; - io->addr += len; - s->packet_transfer_size -= len; + if (io->len == 0) { + io->dma_end(opaque); + return; } - if (io->len <= 0) - io->dma_end(io); + /* launch next transfer */ - if (s->packet_transfer_size <= 0) { - s->status = READY_STAT | SEEK_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO - | ATAPI_INT_REASON_CD; - ide_set_irq(s); + s->io_buffer_size = io->len; + + qemu_sglist_init(&s->sg, io->len / TARGET_PAGE_SIZE + 1); + qemu_sglist_add(&s->sg, io->addr, io->len); + io->addr += io->len; + io->len = 0; + + 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); + if (!m->aiocb) { + qemu_sglist_destroy(&s->sg); + /* Note: media not present is the most likely case */ + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + io->dma_end(opaque); + return; } } -static void pmac_ide_transfer(DBDMA_io *io) +static void pmac_ide_transfer_cb(void *opaque, int ret) { + DBDMA_io *io = opaque; MACIOIDEState *m = io->opaque; IDEState *s = m->ide_if->cur_drive; + int n; int64_t sector_num; - int ret, n; - int len; - if (s->is_cdrom) { - pmac_atapi_read(io); + if (ret < 0) { + m->aiocb = NULL; + qemu_sglist_destroy(&s->sg); + ide_dma_error(s); + io->dma_end(io); return; } - while (io->len > 0 && s->nsector > 0) { + sector_num = ide_get_sector(s); + 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; + } + + /* end of transfer ? */ + if (s->nsector == 0) { + s->status = READY_STAT | SEEK_STAT; + ide_set_irq(s); + } - sector_num = ide_get_sector(s); + /* end of DMA ? */ - n = s->nsector; - if (n > IDE_DMA_BUF_SECTORS) - n = IDE_DMA_BUF_SECTORS; + if (io->len == 0) { + io->dma_end(io); + return; + } - len = n << 9; - if (len > io->len) - len = io->len; - n = (len + 511) >> 9; + /* launch next transfer */ - if (s->is_read) { - ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); - cpu_physical_memory_write(io->addr, s->io_buffer, len); - } else { - cpu_physical_memory_read(io->addr, s->io_buffer, len); - ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); - } + s->io_buffer_index = 0; + s->io_buffer_size = io->len; - if (ret != 0) { - io->dma_end(io); - ide_rw_error(s); - return; - } + qemu_sglist_init(&s->sg, io->len / TARGET_PAGE_SIZE + 1); + qemu_sglist_add(&s->sg, io->addr, io->len); + io->addr += io->len; + io->len = 0; - io->len -= len; - io->addr += len; - ide_set_sector(s, sector_num + n); - s->nsector -= n; - } + if (s->is_read) + m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, + pmac_ide_transfer_cb, io); + else + m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, + pmac_ide_transfer_cb, io); + if (!m->aiocb) + pmac_ide_transfer_cb(io, -1); +} - if (io->len <= 0) - io->dma_end(io); +static void pmac_ide_transfer(DBDMA_io *io) +{ + MACIOIDEState *m = io->opaque; + IDEState *s = m->ide_if->cur_drive; - if (s->nsector <= 0) { - s->status = READY_STAT | SEEK_STAT; - ide_set_irq(s); + s->io_buffer_size = 0; + if (s->is_cdrom) { + pmac_ide_atapi_transfer_cb(io, 0); + return; } - return; + pmac_ide_transfer_cb(io, 0); +} + +static void pmac_ide_flush(DBDMA_io *io) +{ + MACIOIDEState *m = io->opaque; + + if (m->aiocb) + qemu_aio_flush(); } /* PowerMac IDE memory IO */ @@ -3712,7 +3745,7 @@ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq, ide_init2(d->ide_if, hd_table[0], hd_table[1], irq); if (dbdma) - DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, d); + DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d); pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, pmac_ide_write, d); diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index d6608f6893..8e82a2356c 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -160,6 +160,7 @@ typedef struct DBDMA_channel { qemu_irq irq; DBDMA_io io; DBDMA_rw rw; + DBDMA_flush flush; dbdma_cmd current; int processing; } DBDMA_channel; @@ -367,7 +368,8 @@ static void dbdma_end(DBDMA_io *io) current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS])); current->res_count = cpu_to_le16(be32_to_cpu(io->len)); dbdma_cmdptr_save(ch); - ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH); + if (io->is_last) + ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH); conditional_interrupt(ch); conditional_branch(ch); @@ -632,7 +634,7 @@ static void DBDMA_run_bh(void *opaque) } void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, - DBDMA_rw rw, + DBDMA_rw rw, DBDMA_flush flush, void *opaque) { DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan; @@ -642,6 +644,7 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, ch->irq = irq; ch->channel = nchan; ch->rw = rw; + ch->flush = flush; ch->io.opaque = opaque; ch->io.channel = ch; } @@ -687,6 +690,8 @@ dbdma_control_write(DBDMA_channel *ch) if (status & ACTIVE) qemu_bh_schedule(dbdma_bh); + if (status & FLUSH) + ch->flush(&ch->io); } static void dbdma_writel (void *opaque, diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h index 35f65c340a..d236c5b3f2 100644 --- a/hw/mac_dbdma.h +++ b/hw/mac_dbdma.h @@ -22,6 +22,7 @@ typedef struct DBDMA_io DBDMA_io; +typedef void (*DBDMA_flush)(DBDMA_io *io); typedef void (*DBDMA_rw)(DBDMA_io *io); typedef void (*DBDMA_end)(DBDMA_io *io); struct DBDMA_io { @@ -36,7 +37,7 @@ struct DBDMA_io { void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, - DBDMA_rw rw, + DBDMA_rw rw, DBDMA_flush flush, void *opaque); void DBDMA_schedule(void); void* DBDMA_init (int *dbdma_mem_index); |