Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/mvme68k Finally nobble the bus_dmamap_sync() proble...



details:   https://anonhg.NetBSD.org/src/rev/44676c52142e
branches:  trunk
changeset: 510003:44676c52142e
user:      scw <scw%NetBSD.org@localhost>
date:      Wed May 16 19:06:46 2001 +0000

description:
Finally nobble the bus_dmamap_sync() problem with osiop(4).

Basically, bus_dmamap_sync() `PREREAD' needs to flush the cache
for the start and end of the region if it is not aligned to
a cacheline boundary, otherwise a subsequent POSTREAD can *purge*
valid data which was in the cacheline but *outside* the region
passed to bus_dmamap_sync().

Bus snooping doesn't always help here because osiop(4) calls
bus_dmamap_sync() with POSTREAD even if no data was actually
transferred! (And we can't rely on snooping on the 68060 models anyway).

diffstat:

 sys/arch/mvme68k/include/bus_dma.h |   4 +-
 sys/arch/mvme68k/include/pmap.h    |   3 +-
 sys/arch/mvme68k/mvme68k/bus_dma.c |  95 ++++++++++++++++++++++++++++++-------
 sys/arch/mvme68k/mvme68k/pmap.c    |  20 +++++++-
 4 files changed, 100 insertions(+), 22 deletions(-)

diffs (278 lines):

diff -r b2bf51055a5c -r 44676c52142e sys/arch/mvme68k/include/bus_dma.h
--- a/sys/arch/mvme68k/include/bus_dma.h        Wed May 16 18:50:52 2001 +0000
+++ b/sys/arch/mvme68k/include/bus_dma.h        Wed May 16 19:06:46 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: bus_dma.h,v 1.7 2001/03/07 22:42:19 thorpej Exp $  */
+/* $NetBSD: bus_dma.h,v 1.8 2001/05/16 19:06:46 scw Exp $      */
 
 /*
  * This file was extracted from from next68k/include/bus.h
@@ -123,7 +123,7 @@
 
        /* PRIVATE */
        bus_addr_t      _ds_cpuaddr;    /* CPU-relative phys addr of segment */
-       int             _ds_padding;
+       int             _ds_flags;
 };
 typedef struct mvme68k_bus_dma_segment bus_dma_segment_t;
 
diff -r b2bf51055a5c -r 44676c52142e sys/arch/mvme68k/include/pmap.h
--- a/sys/arch/mvme68k/include/pmap.h   Wed May 16 18:50:52 2001 +0000
+++ b/sys/arch/mvme68k/include/pmap.h   Wed May 16 19:06:46 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pmap.h,v 1.20 2001/04/22 23:19:28 thorpej Exp $        */
+/*     $NetBSD: pmap.h,v 1.21 2001/05/16 19:06:46 scw Exp $    */
 
 /* 
  * Copyright (c) 1987 Carnegie-Mellon University
@@ -135,6 +135,7 @@
 
 extern void _pmap_set_page_cacheable __P((struct pmap *, vaddr_t));
 extern void _pmap_set_page_cacheinhibit __P((struct pmap *, vaddr_t));
+extern int _pmap_page_is_cacheable __P((struct pmap *, vaddr_t));
 
 extern struct pv_entry *pv_table;      /* array of entries, one per page */
 
diff -r b2bf51055a5c -r 44676c52142e sys/arch/mvme68k/mvme68k/bus_dma.c
--- a/sys/arch/mvme68k/mvme68k/bus_dma.c        Wed May 16 18:50:52 2001 +0000
+++ b/sys/arch/mvme68k/mvme68k/bus_dma.c        Wed May 16 19:06:46 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: bus_dma.c,v 1.13 2001/05/11 13:01:44 scw Exp $     */
+/* $NetBSD: bus_dma.c,v 1.14 2001/05/16 19:06:47 scw Exp $     */
 
 /*
  * This file was taken from from next68k/dev/bus_dma.c, which was originally
@@ -46,7 +46,7 @@
 
 #include <sys/cdefs.h>                 /* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.13 2001/05/11 13:01:44 scw Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.14 2001/05/16 19:06:47 scw Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -72,12 +72,6 @@
            paddr_t *, int *, int));
 
 /*
- * Initialised in mvme68k/machdep.c according to the host cpu type
- */
-void   (*_bus_dmamap_sync)(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
-           bus_size_t, int);
-
-/*
  * Common function for DMA map creation.  May be called by bus-specific
  * DMA map creation functions.
  */
@@ -162,7 +156,7 @@
        bus_size_t sgsize;
        bus_addr_t curaddr, lastaddr, baddr, bmask;
        vaddr_t vaddr = (vaddr_t)buf;
-       int seg;
+       int seg, cacheable, coherent = BUS_DMA_COHERENT;
 
        lastaddr = *lastaddrp;
        bmask = ~(map->_dm_boundary - 1);
@@ -171,11 +165,20 @@
                /*
                 * Get the physical address for this segment.
                 */
-               if (p != NULL)
+               if (p != NULL) {
                        (void) pmap_extract(p->p_vmspace->vm_map.pmap,
                            vaddr, &curaddr);
-               else
+                       cacheable =
+                           _pmap_page_is_cacheable(p->p_vmspace->vm_map.pmap,
+                               vaddr);
+               } else {
                        (void) pmap_extract(pmap_kernel(),vaddr, &curaddr);
+                       cacheable =
+                           _pmap_page_is_cacheable(pmap_kernel(), vaddr);
+               }
+
+               if (cacheable)
+                       coherent = 0;
 
                /*
                 * Compute the segment size, and adjust counts.
@@ -201,6 +204,8 @@
                        map->dm_segs[seg].ds_addr =
                            map->dm_segs[seg]._ds_cpuaddr = curaddr;
                        map->dm_segs[seg].ds_len = sgsize;
+                       map->dm_segs[seg]._ds_flags =
+                           cacheable ? 0 : BUS_DMA_COHERENT;
                        first = 0;
                } else {
                        if (curaddr == lastaddr &&
@@ -216,6 +221,8 @@
                                map->dm_segs[seg].ds_addr =
                                    map->dm_segs[seg]._ds_cpuaddr = curaddr;
                                map->dm_segs[seg].ds_len = sgsize;
+                               map->dm_segs[seg]._ds_flags =
+                                   cacheable ? 0 : BUS_DMA_COHERENT;
                        }
                }
 
@@ -226,6 +233,8 @@
 
        *segp = seg;
        *lastaddrp = lastaddr;
+       map->_dm_flags &= ~BUS_DMA_COHERENT;
+       map->_dm_flags |= coherent;
 
        /*
         * Did we fit?
@@ -438,6 +447,7 @@
         */
        map->dm_mapsize = 0;
        map->dm_nsegs = 0;
+       map->_dm_flags &= ~BUS_DMA_COHERENT;
 }
 
 /*
@@ -467,11 +477,18 @@
        bus_size_t len;
        int ops;
 {
-       bus_addr_t p, e;
+       bus_addr_t p, e, ps, pe;
        bus_size_t seglen;
        int i;
 
-       if ((ops & (BUS_DMASYNC_PREWRITE | BUS_DMASYNC_POSTREAD)) == 0)
+       /* If the whole DMA map is uncached, do nothing.  */
+       if (map->_dm_flags & BUS_DMA_COHERENT)
+               return;
+
+       /* Short-circuit for unsupported `ops' */
+       if ((ops & (BUS_DMASYNC_PREREAD  |
+                   BUS_DMASYNC_PREWRITE |
+                   BUS_DMASYNC_POSTREAD)) == 0)
                return;
 
        for (i = 0; i < map->dm_nsegs && len > 0; i++) {
@@ -486,9 +503,16 @@
                        seglen = len;
                len -= seglen;
 
+               /* Ignore cache-inhibited segments */
+               if (map->dm_segs[i]._ds_flags & BUS_DMA_COHERENT)
+                       continue;
+
+               ps = map->dm_segs[i]._ds_cpuaddr + offset;
+               pe = ps + seglen;
+
                if (ops & BUS_DMASYNC_PREWRITE) {
-                       p = (map->dm_segs[i]._ds_cpuaddr + offset) & ~0xf;
-                       e = p + ((seglen + 15) & ~0xf);
+                       p = ps & ~0xf;
+                       e = (pe + 15) & ~0xf;
 
                        /* flush cache line (060 too) */
                        while((p < e) && (p % NBPG)) {
@@ -509,9 +533,39 @@
                        }
                }
 
+               /*
+                * Normally, the `PREREAD' flag instructs us to purge the
+                * cache for the specified offset and length. However, if
+                * the offset/length is not aligned to a cacheline boundary,
+                * we may end up purging some legitimate data from the
+                * start/end of the cache. In such a case, *flush* the
+                * cachelines at the start and end of the required region.
+                * We assume someone will do a `POSTREAD' afterwards to
+                * ensure the cache is purged for the remainder of the region.
+                *
+                * Note: Even though the high-end MVME boards support bus-
+                * snooping (well, the 060 isn't *quite* there), the osiop(4)
+                * driver *ALWAYS* issues a `POSTREAD' EVEN IF NO DATA WAS
+                * TRANSFERRED!
+                *
+                * This isn't necessarily a bug, since a SCSI target is free
+                * to disconnect part way through a data-in phase anyway.
+                * Thus, the CPU may never get to snoop the incoming data
+                * before we purge the dmamap region.
+                *
+                * Note #2: All this is necessary on mvme68k because we
+                * normally run the cache in Copy Back mode...
+                */
+               if (ops & BUS_DMASYNC_PREREAD) {
+                       if (ps & 0xf)
+                               DCFL_40(ps);
+                       if (pe & 0xf)
+                               DCFL_40(pe);
+               }
+
                if (ops & BUS_DMASYNC_POSTREAD) {
-                       p = (map->dm_segs[i]._ds_cpuaddr + offset) & ~0xf;
-                       e = p + ((seglen + 15) & ~0xf);
+                       p = ps & ~0xf;
+                       e = (pe + 15) & ~0xf;
 
                        /* purge cache line */
                        while((p < e) && (p % NBPG)) {
@@ -583,6 +637,7 @@
        lastaddr = VM_PAGE_TO_PHYS(m);
        segs[curseg].ds_addr = segs[curseg]._ds_cpuaddr = lastaddr;
        segs[curseg].ds_len = PAGE_SIZE;
+       segs[curseg]._ds_flags = 0;
        m = m->pageq.tqe_next;
 
        for (; m != NULL; m = m->pageq.tqe_next) {
@@ -612,6 +667,7 @@
                        segs[curseg].ds_addr =
                            segs[curseg]._ds_cpuaddr = curaddr;
                        segs[curseg].ds_len = PAGE_SIZE;
+                       segs[curseg]._ds_flags = 0;
                }
                lastaddr = curaddr;
        }
@@ -728,8 +784,11 @@
                            VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
 
                        /* Cache-inhibit the page if necessary */
-                       if ( (flags & BUS_DMA_COHERENT) != 0 )
+                       if ((flags & BUS_DMA_COHERENT) != 0)
                                _pmap_set_page_cacheinhibit(pmap_kernel(), va);
+
+                       segs[curseg]._ds_flags &= ~BUS_DMA_COHERENT;
+                       segs[curseg]._ds_flags |= (flags & BUS_DMA_COHERENT);
                }
        }
        pmap_update();
diff -r b2bf51055a5c -r 44676c52142e sys/arch/mvme68k/mvme68k/pmap.c
--- a/sys/arch/mvme68k/mvme68k/pmap.c   Wed May 16 18:50:52 2001 +0000
+++ b/sys/arch/mvme68k/mvme68k/pmap.c   Wed May 16 19:06:46 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pmap.c,v 1.59 2001/05/13 18:35:19 scw Exp $        */
+/*     $NetBSD: pmap.c,v 1.60 2001/05/16 19:06:47 scw Exp $        */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -2739,6 +2739,24 @@
        }
 }
 
+int
+_pmap_page_is_cacheable(pm, va)
+       struct pmap *pm;
+       vaddr_t va;
+{
+       pt_entry_t *pte;
+
+       if (!pmap_ste_v(pm, va))
+               return (0);
+
+       pte = pmap_pte(pm, va);
+
+       if (pmap_pte_ci(pte))
+               return (0);
+       else
+               return (1);
+}
+
 #ifdef DEBUG
 /*
  * pmap_pvdump:



Home | Main Index | Thread Index | Old Index