]> git.proxmox.com Git - qemu.git/commitdiff
DB-DMA IDE asynchronous I/O
authoraurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 4 Mar 2009 07:20:40 +0000 (07:20 +0000)
committeraurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 4 Mar 2009 07:20:40 +0000 (07:20 +0000)
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

hw/ide.c
hw/mac_dbdma.c
hw/mac_dbdma.h

index f6999b10b35753efcdc78c72821657bb7ea10db6..6ad1d081a6d41e6e3ce2ef3a5c1da23d8464734b 100644 (file)
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -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);
index d6608f6893064fdcfd978f42921211f5085f7d39..8e82a2356cb109127d1b57ec98f67b35c65699c3 100644 (file)
@@ -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,
index 35f65c340a653420ee43aaf2f88a0809b4810e4e..d236c5b3f29eead8b849e85ba23d4f332d2482f9 100644 (file)
@@ -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);