Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/sparc64/dev Support multisegment dmamap sync, adopt...



details:   https://anonhg.NetBSD.org/src/rev/dc5fc0c9bd33
branches:  trunk
changeset: 551594:dc5fc0c9bd33
user:      petrov <petrov%NetBSD.org@localhost>
date:      Mon Sep 08 17:23:15 2003 +0000

description:
Support multisegment dmamap sync, adopted from OpenBSD.

diffstat:

 sys/arch/sparc64/dev/iommu.c |  100 +++++++++++++++++++++++++++++-------------
 1 files changed, 69 insertions(+), 31 deletions(-)

diffs (142 lines):

diff -r ed33a8606016 -r dc5fc0c9bd33 sys/arch/sparc64/dev/iommu.c
--- a/sys/arch/sparc64/dev/iommu.c      Mon Sep 08 17:22:18 2003 +0000
+++ b/sys/arch/sparc64/dev/iommu.c      Mon Sep 08 17:23:15 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: iommu.c,v 1.66 2003/07/15 03:36:05 lukem Exp $ */
+/*     $NetBSD: iommu.c,v 1.67 2003/09/08 17:23:15 petrov Exp $        */
 
 /*
  * Copyright (c) 2001, 2002 Eduardo Horvath
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.66 2003/07/15 03:36:05 lukem Exp $");
+__KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.67 2003/09/08 17:23:15 petrov Exp $");
 
 #include "opt_ddb.h"
 
@@ -901,6 +901,50 @@
        return (0);
 }
 
+
+/*
+ * Flush an individual dma segment, returns non-zero if the streaming buffers
+ * need flushing afterwards.
+ */
+static int
+iommu_dvmamap_sync_range(struct strbuf_ctl *sb, vaddr_t va, bus_size_t len)
+{
+       vaddr_t vaend;
+       struct iommu_state *is = sb->sb_is;
+
+#ifdef DIAGNOSTIC
+       if (va < is->is_dvmabase || va > is->is_dvmaend)
+               panic("invalid va: %llx", (long long)va);
+#endif
+
+       if ((is->is_tsb[IOTSBSLOT(va, is->is_tsbsize)] & IOTTE_STREAM) == 0) {
+               DPRINTF(IDB_BUSDMA, 
+                       ("iommu_dvmamap_sync_range: attempting to flush "
+                        "non-streaming entry\n"));
+               return (0);
+       }
+
+       vaend = (va + len + PGOFSET) & ~PGOFSET;
+       va &= ~PGOFSET;
+
+#ifdef DIAGNOSTIC
+       if (va < is->is_dvmabase || vaend > is->is_dvmaend)
+               panic("invalid va range: %llx to %llx (%x to %x)",
+                   (long long)va, (long long)vaend,
+                   is->is_dvmabase,
+                   is->is_dvmaend);
+#endif
+
+       for ( ; va <= vaend; va += PAGE_SIZE) {
+               DPRINTF(IDB_BUSDMA,
+                   ("iommu_dvmamap_sync_range: flushing va %p\n",
+                   (void *)(u_long)va));
+               iommu_strbuf_flush(sb, va);
+       }
+
+       return (1);
+}
+
 void
 iommu_dvmamap_sync(t, sb, map, offset, len, ops)
        bus_dma_tag_t t;
@@ -910,49 +954,43 @@
        bus_size_t len;
        int ops;
 {
-       struct iommu_state *is = sb->sb_is;
-       vaddr_t va = map->dm_segs[0].ds_addr + offset;
-       int64_t tte;
-       vaddr_t vaend;
+       bus_size_t count;
+       int i, needsflush = 0;
 
        if (!sb->sb_flush)
                return;
 
-       /*
-        * We only support one DMA segment; supporting more makes this code
-        * too unwieldy.
-        */
-       if (map->dm_nsegs > 1)
-               panic("iommu_dvmamap_sync: %d segments", map->dm_nsegs);
+       for (i = 0; i < map->dm_nsegs; i++) {
+               if (offset < map->dm_segs[i].ds_len)
+                       break;
+               offset -= map->dm_segs[i].ds_len;
+       }
 
-       DPRINTF(IDB_SYNC,
-           ("iommu_dvmamap_sync: syncing va %p len %lu "
-            "ops 0x%x\n", (void *)(u_long)va, (u_long)len, ops));
+       if (i == map->dm_nsegs)
+               panic("iommu_dvmamap_sync: segment too short %lu", offset);
 
        if (ops & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_POSTWRITE)) {
                /* Nothing to do */;
        }
 
        if (ops & (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_PREWRITE)) {
-#ifdef DIAGNOSTIC
-               if (va < is->is_dvmabase || va >= is->is_dvmaend)
-                       panic("iommu_dvmamap_sync: invalid dva %lx", va);
-#endif
-               tte = is->is_tsb[IOTSBSLOT(va, is->is_tsbsize)];
-
-               /* if we have a streaming buffer, flush it here first */
-               if ((tte & IOTTE_STREAM) && sb->sb_flush) {
-                       vaend = (va + len + PGOFSET) & ~PGOFSET;
 
-                       for (va &= ~PGOFSET; va <= vaend; va += PAGE_SIZE) {
-                               DPRINTF(IDB_BUSDMA,
-                                       ("iommu_dvmamap_sync: flushing va %p\n",
-                                        (void *)(u_long)va));
-                               iommu_strbuf_flush(sb, va);
-                       }
+               for (; len > 0 && i < map->dm_nsegs; i++) {
+                       count = MIN(map->dm_segs[i].ds_len - offset, len);
+                       if (count > 0 && 
+                           iommu_dvmamap_sync_range(sb,
+                               map->dm_segs[i].ds_addr + offset, count))
+                               needsflush = 1;
+                       offset = 0;
+                       len -= count;
+               }
+#ifdef DIAGNOSTIC
+               if (i == map->dm_nsegs && len > 0)
+                       panic("iommu_dvmamap_sync: leftover %lu", len);
+#endif
 
+               if (needsflush)
                        iommu_strbuf_flush_done(sb);
-               }
        }
 }
 



Home | Main Index | Thread Index | Old Index