qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [6681] DB-DMA IDE asynchronous I/O


From: Aurelien Jarno
Subject: [Qemu-devel] [6681] DB-DMA IDE asynchronous I/O
Date: Wed, 04 Mar 2009 07:20:42 +0000

Revision: 6681
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=6681
Author:   aurel32
Date:     2009-03-04 07:20:40 +0000 (Wed, 04 Mar 2009)
Log Message:
-----------
DB-DMA IDE asynchronous I/O

Signed-off-by: Laurent Vivier <address@hidden>
Signed-off-by: Aurelien Jarno <address@hidden>

Modified Paths:
--------------
    trunk/hw/ide.c
    trunk/hw/mac_dbdma.c
    trunk/hw/mac_dbdma.h

Modified: trunk/hw/ide.c
===================================================================
--- trunk/hw/ide.c      2009-03-03 20:11:43 UTC (rev 6680)
+++ trunk/hw/ide.c      2009-03-04 07:20:40 UTC (rev 6681)
@@ -3429,112 +3429,145 @@
 
 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) {
+    if (ret < 0) {
+        m->aiocb = NULL;
+        qemu_sglist_destroy(&s->sg);
+        ide_atapi_io_error(s, ret);
+        io->dma_end(opaque);
+        return;
+    }
 
-        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 (s->io_buffer_size > 0) {
+        m->aiocb = NULL;
+        qemu_sglist_destroy(&s->sg);
 
-        if (len > io->len)
-            len = io->len;
+        s->packet_transfer_size -= s->io_buffer_size;
 
-        cpu_physical_memory_write(io->addr,
-                                  s->io_buffer + m->stream_index, len);
+        s->io_buffer_index += s->io_buffer_size;
+       s->lba += s->io_buffer_index >> 11;
+        s->io_buffer_index &= 0x7ff;
+    }
 
-       /* db-dma can ask for 512 bytes whereas block size is 2048... */
+    if (s->packet_transfer_size <= 0)
+        ide_atapi_cmd_ok(s);
 
-        m->stream_index += len;
-        s->lba += m->stream_index / s->cd_sector_size;
-        m->stream_index %= s->cd_sector_size;
-
-        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;
+    }
 
-        sector_num = ide_get_sector(s);
+    /* end of transfer ? */
+    if (s->nsector == 0) {
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s);
+    }
 
-        n = s->nsector;
-        if (n > IDE_DMA_BUF_SECTORS)
-            n = IDE_DMA_BUF_SECTORS;
+    /* end of DMA ? */
 
-        len = n << 9;
-        if (len > io->len)
-            len = io->len;
-        n = (len + 511) >> 9;
+    if (io->len == 0) {
+        io->dma_end(io);
+       return;
+    }
 
-        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);
-        }
+    /* launch next transfer */
 
-        if (ret != 0) {
-            io->dma_end(io);
-            ide_rw_error(s);
-            return;
-        }
+    s->io_buffer_index = 0;
+    s->io_buffer_size = io->len;
 
-        io->len -= len;
-        io->addr += len;
-        ide_set_sector(s, sector_num + n);
-        s->nsector -= n;
-    }
+    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;
 
-    if (io->len <= 0)
-        io->dma_end(io);
+    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 (s->nsector <= 0) {
-        s->status = READY_STAT | SEEK_STAT;
-        ide_set_irq(s);
+static void pmac_ide_transfer(DBDMA_io *io)
+{
+    MACIOIDEState *m = io->opaque;
+    IDEState *s = m->ide_if->cur_drive;
+
+    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 */
 static void pmac_ide_writeb (void *opaque,
                              target_phys_addr_t addr, uint32_t val)
@@ -3712,7 +3745,7 @@
     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);

Modified: trunk/hw/mac_dbdma.c
===================================================================
--- trunk/hw/mac_dbdma.c        2009-03-03 20:11:43 UTC (rev 6680)
+++ trunk/hw/mac_dbdma.c        2009-03-04 07:20:40 UTC (rev 6681)
@@ -160,6 +160,7 @@
     qemu_irq irq;
     DBDMA_io io;
     DBDMA_rw rw;
+    DBDMA_flush flush;
     dbdma_cmd current;
     int processing;
 } DBDMA_channel;
@@ -367,7 +368,8 @@
     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 @@
 }
 
 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 @@
     ch->irq = irq;
     ch->channel = nchan;
     ch->rw = rw;
+    ch->flush = flush;
     ch->io.opaque = opaque;
     ch->io.channel = ch;
 }
@@ -687,6 +690,8 @@
 
     if (status & ACTIVE)
         qemu_bh_schedule(dbdma_bh);
+    if (status & FLUSH)
+        ch->flush(&ch->io);
 }
 
 static void dbdma_writel (void *opaque,

Modified: trunk/hw/mac_dbdma.h
===================================================================
--- trunk/hw/mac_dbdma.h        2009-03-03 20:11:43 UTC (rev 6680)
+++ trunk/hw/mac_dbdma.h        2009-03-04 07:20:40 UTC (rev 6681)
@@ -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 @@
 
 
 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);





reply via email to

[Prev in Thread] Current Thread [Next in Thread]