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 @@
®s->iommu_tsb, ®s->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