qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Alexander Graf <agraf@suse.de>
To: qemu-ppc@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>,
	programmingkidx@gmail.com, mark.cave-ayland@ilande.co.uk,
	qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 14/15] PPC: dbdma: Support unaligned DMA access
Date: Sun, 30 Jun 2013 03:27:08 +0200	[thread overview]
Message-ID: <1372555629-17976-15-git-send-email-agraf@suse.de> (raw)
In-Reply-To: <1372555629-17976-1-git-send-email-agraf@suse.de>

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 <agraf@suse.de>
---
 hw/ide/macio.c             | 128 ++++++++++++++++++++++++++++++++++++++++++---
 include/hw/ppc/mac_dbdma.h |   3 ++
 2 files changed, 124 insertions(+), 7 deletions(-)

diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 095e1f1..202df06 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -51,11 +51,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;
     }
 
@@ -80,8 +82,30 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
         s->io_buffer_index &= 0x7ff;
     }
 
+    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 */
+        pmac_ide_atapi_transfer_cb(opaque, 0);
+        return;
+    }
+
     /* end of transfer ? */
-    if (s->packet_transfer_size <= 0) {
+    if (!s->packet_transfer_size) {
         MACIO_DPRINTF("end of transfer\n");
         ide_atapi_cmd_ok(s);
         m->dma_active = false;
@@ -95,14 +119,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, 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",
@@ -125,14 +175,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;
     }
 
@@ -155,8 +207,34 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
         s->nsector -= n;
     }
 
+    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;
+    }
+
     /* end of transfer ? */
-    if (s->nsector == 0) {
+    if (s->nsector == 0 && !io->remainder_len) {
         MACIO_DPRINTF("end of transfer\n");
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
@@ -174,13 +252,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, 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 8ad1b6e..ad4d826 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 */
     int processing;
+    /* unaligned last sector of a request */
+    uint8_t remainder[0x200];
+    int remainder_len;
 };
 
 /*
-- 
1.8.1.4

      parent reply	other threads:[~2013-06-30  1:27 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-06-30  1:26 [Qemu-devel] [PATCH 00/15] PPC: Mac OS X guest bringup Alexander Graf
2013-06-30  1:26 ` [Qemu-devel] [PATCH 01/15] PPC: Mac: Fix guest exported tbfreq values Alexander Graf
2013-06-30  1:26 ` [Qemu-devel] [PATCH 02/15] PPC: g3beige: Move secondary IDE bus to mac-io Alexander Graf
2013-06-30  6:33   ` Andreas Färber
2013-06-30 23:18     ` Alexander Graf
2013-06-30  1:26 ` [Qemu-devel] [PATCH 03/15] PPC: Macio: Replace tabs with spaces Alexander Graf
2013-06-30  1:26 ` [Qemu-devel] [PATCH 04/15] PPC: dbdma: " Alexander Graf
2013-06-30  6:35   ` Andreas Färber
2013-06-30 11:21     ` Alexander Graf
2013-06-30  1:26 ` [Qemu-devel] [PATCH 05/15] PPC: Mac: Add debug prints in macio and dbdma code Alexander Graf
2013-06-30  6:42   ` Andreas Färber
2013-06-30 23:30     ` Alexander Graf
2013-06-30  1:27 ` [Qemu-devel] [PATCH 06/15] PPC: dbdma: Fix debug print Alexander Graf
2013-06-30  1:27 ` [Qemu-devel] [PATCH 07/15] PPC: dbdma: Allow new commands in RUN state Alexander Graf
2013-06-30  1:27 ` [Qemu-devel] [PATCH 08/15] PPC: dbdma: Move defines into header file Alexander Graf
2013-06-30  1:27 ` [Qemu-devel] [PATCH 09/15] PPC: dbdma: Introduce kick function Alexander Graf
2013-06-30  1:27 ` [Qemu-devel] [PATCH 10/15] PPC: dbdma: Move static bh variable to device struct Alexander Graf
2013-06-30  1:27 ` [Qemu-devel] [PATCH 11/15] PPC: dbdma: macio: Add DMA callback Alexander Graf
2013-06-30  1:27 ` [Qemu-devel] [PATCH 12/15] PPC: dbdma: Move processing to io Alexander Graf
2013-06-30  6:48   ` Andreas Färber
2013-06-30 23:35     ` Alexander Graf
2013-06-30  1:27 ` [Qemu-devel] [PATCH 13/15] PPC: dbdma: Wait for DMA until we have data Alexander Graf
2013-06-30  1:27 ` Alexander Graf [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1372555629-17976-15-git-send-email-agraf@suse.de \
    --to=agraf@suse.de \
    --cc=kwolf@redhat.com \
    --cc=mark.cave-ayland@ilande.co.uk \
    --cc=programmingkidx@gmail.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).