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 large (>1 page) DVMA maps so Ul...



details:   https://anonhg.NetBSD.org/src/rev/752eea278963
branches:  trunk
changeset: 487492:752eea278963
user:      eeh <eeh%NetBSD.org@localhost>
date:      Thu Jun 08 16:17:29 2000 +0000

description:
Support large (>1 page) DVMA maps so UltraSPARC IIi will work.

diffstat:

 sys/arch/sparc64/dev/iommu.c  |  84 +++++++++++++++++++++++++++++-------------
 sys/arch/sparc64/dev/psycho.c |  65 ++++++++++++++++++++++++++------
 2 files changed, 109 insertions(+), 40 deletions(-)

diffs (293 lines):

diff -r 03986ac1211b -r 752eea278963 sys/arch/sparc64/dev/iommu.c
--- a/sys/arch/sparc64/dev/iommu.c      Thu Jun 08 15:23:44 2000 +0000
+++ b/sys/arch/sparc64/dev/iommu.c      Thu Jun 08 16:17:29 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: iommu.c,v 1.10 2000/05/17 09:53:53 mrg Exp $   */
+/*     $NetBSD: iommu.c,v 1.11 2000/06/08 16:17:29 eeh Exp $   */
 
 /*
  * Copyright (c) 1999, 2000 Matthew R. Green
@@ -112,7 +112,6 @@
 /*
  * UltraSPARC IOMMU support; used by both the sbus and pci code.
  */
-
 #include "opt_ddb.h"
 
 #include <sys/param.h>
@@ -141,6 +140,7 @@
 #define DPRINTF(l, s)
 #endif
 
+
 /*
  * initialise the UltraSPARC IOMMU (SBUS or PCI):
  *     - allocate and setup the iotsb.
@@ -154,6 +154,12 @@
        struct iommu_state *is;
        int tsbsize;
 {
+       bus_space_handle_t vtsbp;
+       psize_t size;
+       vaddr_t va;
+       paddr_t pa;
+       vm_page_t m;
+       struct pglist mlist;
 
        /*
         * Setup the iommu.
@@ -161,18 +167,6 @@
         * The sun4u iommu is part of the SBUS or PCI controller so we
         * will deal with it here..
         *
-        * First we need to allocate a IOTSB.  Problem is that the IOMMU
-        * can only access the IOTSB by physical address, so all the 
-        * pages must be contiguous.  Luckily, the smallest IOTSB size
-        * is one 8K page.
-        */
-       if (tsbsize != 0)
-               panic("tsbsize != 0; FIX ME");  /* XXX */
-       
-       /* we want 8K pages */
-       is->is_cr = IOMMUCR_8KPG | IOMMUCR_EN;
-       /*
-        *
         * The IOMMU address space always ends at 0xffffe000, but the starting
         * address depends on the size of the map.  The map size is 1024 * 2 ^
         * is->is_tsbsize entries, where each entry is 8 bytes.  The start of
@@ -182,11 +176,41 @@
         * NULL DMA pointer will be translated by the first page of the IOTSB.
         * To trap bugs we'll skip the first entry in the IOTSB.
         */
-       is->is_dvmabase = IOTSB_VSTART(is->is_tsbsize) + NBPG;
+       is->is_cr = (tsbsize << 16) | IOMMUCR_EN;
        is->is_tsbsize = tsbsize;
-       is->is_tsb = malloc(NBPG, M_DMAMAP, M_WAITOK);  /* XXX */
-       (void) pmap_extract(pmap_kernel(), (vaddr_t)is->is_tsb,
-           (paddr_t *)&is->is_ptsb);
+       is->is_dvmabase = IOTSB_VSTART(is->is_tsbsize) + NBPG;
+
+       /*
+        * Allocate memory for I/O pagetables.
+        * This takes 64K of contiguous physical memory to map 64M of
+        * DVMA space (starting at IOMMU_DVMA_BASE).
+        * The table must be aligned on a (-IOMMU_DVMA_BASE/pagesize)
+        * boundary (i.e. 64K for 64M of DVMA space).
+        */
+
+       size = NBPG<<(is->is_tsbsize);
+       TAILQ_INIT(&mlist);
+       if (uvm_pglistalloc((psize_t)size, (paddr_t)0, (paddr_t)-1,
+               (paddr_t)NBPG, (paddr_t)0, &mlist, 1, 0) != 0)
+               panic("iommu_init: no memory");
+
+       va = uvm_km_valloc(kernel_map, size);
+       if (va == 0)
+               panic("iommu_init: no memory");
+       is->is_tsb = (int64_t *)va;
+
+       m = TAILQ_FIRST(&mlist);
+       is->is_ptsb = VM_PAGE_TO_PHYS(m);
+
+       /* Map the pages */
+       for (; m != NULL; m = TAILQ_NEXT(m,pageq)) {
+               pa = VM_PAGE_TO_PHYS(m);
+               pmap_enter(pmap_kernel(), va, pa | PMAP_NVC,
+                       VM_PROT_READ|VM_PROT_WRITE,
+                       VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED);
+               va += NBPG;
+       }
+       bzero(is->is_tsb, size);
 
 #ifdef DEBUG
        if (iommudebug & IDB_DVMA)
@@ -199,8 +223,8 @@
                       &regs->iommu_tsb, &regs->iommu_flush);
                cr = regs->iommu_cr;
                tsb = regs->iommu_tsb;
-               printf("iommu cr=%lx tsb=%lx\n", (long)cr, (long)tsb);
-               printf("TSB base %p phys %p\n", (long)is->is_tsb, (long)is->is_ptsb);
+               printf("iommu cr=%qx tsb=%qx\n", cr, tsb);
+               printf("TSB base %p phys %qx\n", (void *)is->is_tsb, (u_int64_t)is->is_ptsb);
                delay(1000000); /* 1 s */
        }
 #endif
@@ -220,6 +244,9 @@
        /*
         * Now all the hardware's working we need to allocate a dvma map.
         */
+       printf("DVMA map: %x to %x\n", 
+               (unsigned int)is->is_dvmabase,
+               (unsigned int)IOTSB_VEND);
        is->is_dvmamap = extent_create(name,
                                       is->is_dvmabase, IOTSB_VEND,
                                       M_DEVBUF, 0, 0, EX_NOWAIT);
@@ -236,8 +263,11 @@
 {
 
        /* Need to do 64-bit stores */
-       bus_space_write_8(is->is_bustag, &is->is_iommu->iommu_cr, 0, is->is_cr);
        bus_space_write_8(is->is_bustag, &is->is_iommu->iommu_tsb, 0, is->is_ptsb);
+       /* Enable IOMMU in diagnostic mode */
+       bus_space_write_8(is->is_bustag, &is->is_iommu->iommu_cr, 0, 
+               is->is_cr|IOMMUCR_DE);
+
 
        if (!is->is_sb)
                return;
@@ -466,17 +496,17 @@
            map->_dm_boundary, EX_NOWAIT, (u_long *)&dvmaddr);
        splx(s);
 
-       if (err != 0)
-               return (err);
-
 #ifdef DEBUG
-       if (dvmaddr == (bus_addr_t)-1)  
+       if (err || (dvmaddr == (bus_addr_t)-1)) 
        { 
                printf("iommu_dvmamap_load(): extent_alloc(%d, %x) failed!\n",
                    sgsize, flags);
                Debugger();
        }               
 #endif 
+       if (err != 0)
+               return (err);
+
        if (dvmaddr == (bus_addr_t)-1)
                return (ENOMEM);
 
@@ -511,8 +541,8 @@
                        sgsize = buflen;
 
                DPRINTF(IDB_DVMA,
-                   ("iommu_dvmamap_load: map %p loading va %lx at pa %lx\n",
-                   map, (long)dvmaddr, (long)(curaddr & ~(NBPG-1))));
+                   ("iommu_dvmamap_load: map %p loading va %p dva %lx at pa %lx\n",
+                   map, (void *)vaddr, (long)dvmaddr, (long)(curaddr&~(NBPG-1))));
                iommu_enter(is, trunc_page(dvmaddr), trunc_page(curaddr),
                    flags);
                        
diff -r 03986ac1211b -r 752eea278963 sys/arch/sparc64/dev/psycho.c
--- a/sys/arch/sparc64/dev/psycho.c     Thu Jun 08 15:23:44 2000 +0000
+++ b/sys/arch/sparc64/dev/psycho.c     Thu Jun 08 16:17:29 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: psycho.c,v 1.12 2000/05/24 20:27:52 eeh Exp $  */
+/*     $NetBSD: psycho.c,v 1.13 2000/06/08 16:17:29 eeh Exp $  */
 
 /*
  * Copyright (c) 1999, 2000 Matthew R. Green
@@ -84,7 +84,7 @@
 static void psycho_get_intmapmask __P((int, struct psycho_interrupt_map_mask *));
 
 /* IOMMU support */
-static void psycho_iommu_init __P((struct psycho_softc *));
+static void psycho_iommu_init __P((struct psycho_softc *, int));
 
 /*
  * bus space and bus dma support for UltraSPARC `psycho'.  note that most
@@ -362,8 +362,32 @@
 
        printf("\n");
 
+
+       /* 
+        * SABRE seems to be buggy.  It only appears to work with 128K IOTSB.
+        * I have tried other sizes but they just don't seem to work.  Maybe
+        * more testing is needed.
+        *
+        * The PROM reserves a certain amount of RAM for an IOTSB.  The
+        * problem is that it's not necessarily the full 128K.  So we'll free
+        * this space up and let iommu_init() allocate a full mapping.
+        *
+        * (Otherwise we would need to change the iommu code to handle a
+        * preallocated TSB that may not cover the entire DVMA address
+        * space...
+        *
+        * The information about this memory is shared between the
+        * `virtual-dma' property, which describes the base and size of the
+        * virtual region, and the IOMMU base address register which is the
+        * only known pointer to the RAM.  To free up the memory you need to
+        * read the base addres register and then calculate the size by taking
+        * the virtual size and dividing it by 1K to get the size in bytes.
+        * This range can then be freed up by calling uvm_page_physload().
+        * 
+        */
+
        /* and finally start up the IOMMU ... */
-       psycho_iommu_init(sc);
+       psycho_iommu_init(sc, 7);
 
        /*
         * get us a config space tag, and punch in the physical address
@@ -512,7 +536,13 @@
         * macros to provide the proper ASI based on the bus tag.
         */
        if (sc->sc_mode == PSYCHO_MODE_PSYCHO_A) {
-               psycho_iommu_init(sc);
+               /*
+                * We should calculate a TSB size based on amount of RAM
+                * and number of bus controllers.
+                *
+                * For the moment, 32KB should be more than enough.
+                */
+               psycho_iommu_init(sc, 2);
 
                sc->sc_configtag = psycho_alloc_config_tag(sc->sc_psycho_this);
                if (bus_space_map2(sc->sc_bustag,
@@ -628,19 +658,20 @@
  * initialise the IOMMU..
  */
 void
-psycho_iommu_init(sc)
+psycho_iommu_init(sc, tsbsize)
        struct psycho_softc *sc;
+       int tsbsize;
 {
        char *name;
 
        /* punch in our copies */
        sc->sc_is.is_bustag = sc->sc_bustag;
        sc->sc_is.is_iommu = &sc->sc_regs->psy_iommu;
-       /* IIi does not have streaming buffers */
-       if (sc->sc_mode != PSYCHO_MODE_SABRE)
+
+       if (getproplen(sc->sc_node, "no-streaming-cache") < 0)
+               sc->sc_is.is_sb = 0;
+       else
                sc->sc_is.is_sb = &sc->sc_regs->psy_iommu_strbuf;
-       else
-               sc->sc_is.is_sb = 0;
 
        /* give us a nice name.. */
        name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
@@ -648,8 +679,7 @@
                panic("couldn't malloc iommu name");
        snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname);
 
-       /* XXX XXX XXX FIX ME tsbsize XXX XXX XXX */
-       iommu_init(name, &sc->sc_is, 0);
+       iommu_init(name, &sc->sc_is, tsbsize);
 }
 
 /*
@@ -1025,8 +1055,17 @@
        struct psycho_pbm *pp = (struct psycho_pbm *)t->_cookie;
        struct psycho_softc *sc = pp->pp_sc;
 
-       iommu_dvmamap_sync(t, &sc->sc_is, map, offset, len, ops);
-       bus_dmamap_sync(t->_parent, map, offset, len, ops);
+       if (ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) {
+               /* Flush the CPU then the IOMMU */
+               bus_dmamap_sync(t->_parent, map, offset, len, ops);
+               iommu_dvmamap_sync(t, &sc->sc_is, map, offset, len, ops);
+       }
+       if (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) {
+               /* Flush the IOMMU then the CPU */
+               iommu_dvmamap_sync(t, &sc->sc_is, map, offset, len, ops);
+               bus_dmamap_sync(t->_parent, map, offset, len, ops);
+       }
+
 }
 
 int



Home | Main Index | Thread Index | Old Index