Move the DMA tag and DVMA map into the iommu_softc, and pass the

iommu_softc in the DMA tag cookie.  This gives us a chance of supporting
systems (such as the Sun4d) which have multiple iommus.
This commit is contained in:
thorpej 2002-08-25 16:02:53 +00:00
parent f54ddc3c17
commit 51b546d0bb
2 changed files with 50 additions and 71 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: iommu.c,v 1.66 2002/08/23 02:53:12 thorpej Exp $ */ /* $NetBSD: iommu.c,v 1.67 2002/08/25 16:02:53 thorpej Exp $ */
/* /*
* Copyright (c) 1996 * Copyright (c) 1996
@ -65,17 +65,15 @@ struct iommu_softc {
bus_addr_t sc_dvmabase; bus_addr_t sc_dvmabase;
iopte_t *sc_ptes; iopte_t *sc_ptes;
int sc_hasiocache; int sc_hasiocache;
};
struct iommu_softc *iommu_sc;/*XXX*/
int has_iocache;
/* /*
* Note: operations on the extent map are being protected with * Note: operations on the extent map are being protected with
* splhigh(), since we cannot predict at which interrupt priority * splhigh(), since we cannot predict at which interrupt priority
* our clients will run. * our clients will run.
*/ */
struct extent *iommu_dvmamap; struct sparc_bus_dma_tag sc_dmatag;
struct extent *sc_dvmamap;
};
static int has_iocache;
/* autoconfiguration driver */ /* autoconfiguration driver */
int iommu_print __P((void *, const char *)); int iommu_print __P((void *, const char *));
@ -109,27 +107,9 @@ int iommu_dmamem_map __P((bus_dma_tag_t tag, bus_dma_segment_t *segs,
int nsegs, size_t size, caddr_t *kvap, int flags)); int nsegs, size_t size, caddr_t *kvap, int flags));
paddr_t iommu_dmamem_mmap __P((bus_dma_tag_t tag, bus_dma_segment_t *segs, paddr_t iommu_dmamem_mmap __P((bus_dma_tag_t tag, bus_dma_segment_t *segs,
int nsegs, off_t off, int prot, int flags)); int nsegs, off_t off, int prot, int flags));
int iommu_dvma_alloc(bus_dmamap_t, vaddr_t, bus_size_t, int, int iommu_dvma_alloc(struct iommu_softc *, bus_dmamap_t, vaddr_t,
bus_addr_t *, bus_size_t *); bus_size_t, int, bus_addr_t *, bus_size_t *);
struct sparc_bus_dma_tag iommu_dma_tag = {
NULL,
iommu_dmamap_create,
_bus_dmamap_destroy,
iommu_dmamap_load,
iommu_dmamap_load_mbuf,
iommu_dmamap_load_uio,
iommu_dmamap_load_raw,
iommu_dmamap_unload,
iommu_dmamap_sync,
_bus_dmamem_alloc,
_bus_dmamem_free,
iommu_dmamem_map,
_bus_dmamem_unmap,
iommu_dmamem_mmap
};
/* /*
* Print the location of some iommu-attached device (called just * Print the location of some iommu-attached device (called just
* before attaching that device). If `iommu' is not NULL, the * before attaching that device). If `iommu' is not NULL, the
@ -173,6 +153,7 @@ iommu_attach(parent, self, aux)
#if defined(SUN4M) #if defined(SUN4M)
struct iommu_softc *sc = (struct iommu_softc *)self; struct iommu_softc *sc = (struct iommu_softc *)self;
struct mainbus_attach_args *ma = aux; struct mainbus_attach_args *ma = aux;
struct sparc_bus_dma_tag *dmat = &sc->sc_dmatag;
bus_space_handle_t bh; bus_space_handle_t bh;
int node; int node;
int js1_implicit_iommu; int js1_implicit_iommu;
@ -183,15 +164,21 @@ iommu_attach(parent, self, aux)
struct vm_page *m; struct vm_page *m;
vaddr_t va; vaddr_t va;
/* dmat->_cookie = sc;
* XXX there is only one iommu, for now -- do not know how to dmat->_dmamap_create = iommu_dmamap_create;
* address children on others dmat->_dmamap_destroy = _bus_dmamap_destroy;
*/ dmat->_dmamap_load = iommu_dmamap_load;
if (sc->sc_dev.dv_unit > 0) { dmat->_dmamap_load_mbuf = iommu_dmamap_load_mbuf;
printf(" unsupported\n"); dmat->_dmamap_load_uio = iommu_dmamap_load_uio;
return; dmat->_dmamap_load_raw = iommu_dmamap_load_raw;
} dmat->_dmamap_unload = iommu_dmamap_unload;
iommu_sc = sc; dmat->_dmamap_sync = iommu_dmamap_sync;
dmat->_dmamem_alloc = _bus_dmamem_alloc;
dmat->_dmamem_free = _bus_dmamem_free;
dmat->_dmamem_map = iommu_dmamem_map;
dmat->_dmamem_unmap = _bus_dmamem_unmap;
dmat->_dmamem_mmap = iommu_dmamem_mmap;
/* /*
* JS1/OF device tree does not have an iommu node and sbus * JS1/OF device tree does not have an iommu node and sbus
@ -213,12 +200,8 @@ iommu_attach(parent, self, aux)
* XXX struct iommureg is bigger than ra->ra_len; what are the * XXX struct iommureg is bigger than ra->ra_len; what are the
* other fields for? * other fields for?
*/ */
if (bus_space_map( if (bus_space_map(ma->ma_bustag, ma->ma_paddr,
ma->ma_bustag, sizeof(struct iommureg), 0, &bh) != 0) {
ma->ma_paddr,
sizeof(struct iommureg),
0,
&bh) != 0) {
printf("iommu_attach: cannot map registers\n"); printf("iommu_attach: cannot map registers\n");
return; return;
} }
@ -297,10 +280,10 @@ iommu_attach(parent, self, aux)
sc->sc_pagesize, sc->sc_pagesize,
sc->sc_range >> 20); sc->sc_range >> 20);
iommu_dvmamap = extent_create("iommudvma", sc->sc_dvmamap = extent_create("iommudvma",
IOMMU_DVMA_BASE, IOMMU_DVMA_END, IOMMU_DVMA_BASE, IOMMU_DVMA_END,
M_DEVBUF, 0, 0, EX_NOWAIT); M_DEVBUF, 0, 0, EX_NOWAIT);
if (iommu_dvmamap == NULL) if (sc->sc_dvmamap == NULL)
panic("iommu: unable to allocate DVMA map"); panic("iommu: unable to allocate DVMA map");
/* /*
@ -316,7 +299,7 @@ iommu_attach(parent, self, aux)
/* Propagate BUS & DMA tags */ /* Propagate BUS & DMA tags */
ia.iom_bustag = ma->ma_bustag; ia.iom_bustag = ma->ma_bustag;
ia.iom_dmatag = &iommu_dma_tag; ia.iom_dmatag = &sc->sc_dmatag;
ia.iom_name = "sbus"; ia.iom_name = "sbus";
ia.iom_node = node; ia.iom_node = node;
@ -338,7 +321,7 @@ iommu_attach(parent, self, aux)
/* Propagate BUS & DMA tags */ /* Propagate BUS & DMA tags */
ia.iom_bustag = ma->ma_bustag; ia.iom_bustag = ma->ma_bustag;
ia.iom_dmatag = &iommu_dma_tag; ia.iom_dmatag = &sc->sc_dmatag;
ia.iom_node = node; ia.iom_node = node;
@ -412,12 +395,9 @@ iommu_copy_prom_entries(sc)
} }
#endif #endif
void static void
iommu_enter(dva, pa) iommu_enter(struct iommu_softc *sc, bus_addr_t dva, paddr_t pa)
bus_addr_t dva;
paddr_t pa;
{ {
struct iommu_softc *sc = iommu_sc;
int pte; int pte;
/* This routine relies on the fact that sc->sc_pagesize == PAGE_SIZE */ /* This routine relies on the fact that sc->sc_pagesize == PAGE_SIZE */
@ -435,14 +415,11 @@ iommu_enter(dva, pa)
} }
/* /*
* iommu_clear: clears mappings created by iommu_enter * iommu_remove: removes mappings created by iommu_enter
*/ */
void static void
iommu_remove(dva, len) iommu_remove(struct iommu_softc *sc, bus_addr_t dva, bus_size_t len)
bus_addr_t dva;
bus_size_t len;
{ {
struct iommu_softc *sc = iommu_sc;
u_int pagesz = sc->sc_pagesize; u_int pagesz = sc->sc_pagesize;
bus_addr_t base = sc->sc_dvmabase; bus_addr_t base = sc->sc_dvmabase;
@ -526,6 +503,7 @@ iommu_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
int flags; int flags;
bus_dmamap_t *dmamp; bus_dmamap_t *dmamp;
{ {
struct iommu_softc *sc = t->_cookie;
bus_dmamap_t map; bus_dmamap_t map;
int error; int error;
@ -539,8 +517,8 @@ iommu_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
map->_dm_ex_end = D24_DVMA_END; map->_dm_ex_end = D24_DVMA_END;
} else { } else {
/* Enable allocations from the entire map */ /* Enable allocations from the entire map */
map->_dm_ex_start = iommu_dvmamap->ex_start; map->_dm_ex_start = sc->sc_dvmamap->ex_start;
map->_dm_ex_end = iommu_dvmamap->ex_end; map->_dm_ex_end = sc->sc_dvmamap->ex_end;
} }
*dmamp = map; *dmamp = map;
@ -551,7 +529,8 @@ iommu_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
* Internal routine to allocate space in the IOMMU map. * Internal routine to allocate space in the IOMMU map.
*/ */
int int
iommu_dvma_alloc(map, va, len, flags, dvap, sgsizep) iommu_dvma_alloc(sc, map, va, len, flags, dvap, sgsizep)
struct iommu_softc *sc;
bus_dmamap_t map; bus_dmamap_t map;
vaddr_t va; vaddr_t va;
bus_size_t len; bus_size_t len;
@ -578,7 +557,7 @@ iommu_dvma_alloc(map, va, len, flags, dvap, sgsizep)
align = dvma_cachealign ? dvma_cachealign : map->_dm_align; align = dvma_cachealign ? dvma_cachealign : map->_dm_align;
s = splhigh(); s = splhigh();
error = extent_alloc_subregion1(iommu_dvmamap, error = extent_alloc_subregion1(sc->sc_dvmamap,
map->_dm_ex_start, map->_dm_ex_end, map->_dm_ex_start, map->_dm_ex_end,
sgsize, align, va & (align-1), sgsize, align, va & (align-1),
map->_dm_boundary, map->_dm_boundary,
@ -603,6 +582,7 @@ iommu_dmamap_load(t, map, buf, buflen, p, flags)
struct proc *p; struct proc *p;
int flags; int flags;
{ {
struct iommu_softc *sc = t->_cookie;
bus_size_t sgsize; bus_size_t sgsize;
bus_addr_t dva; bus_addr_t dva;
vaddr_t va = (vaddr_t)buf; vaddr_t va = (vaddr_t)buf;
@ -616,7 +596,7 @@ iommu_dmamap_load(t, map, buf, buflen, p, flags)
map->dm_nsegs = 0; map->dm_nsegs = 0;
/* Allocate IOMMU resources */ /* Allocate IOMMU resources */
if ((error = iommu_dvma_alloc(map, va, buflen, flags, if ((error = iommu_dvma_alloc(sc, map, va, buflen, flags,
&dva, &sgsize)) != 0) &dva, &sgsize)) != 0)
return (error); return (error);
@ -643,7 +623,7 @@ iommu_dmamap_load(t, map, buf, buflen, p, flags)
*/ */
(void) pmap_extract(pmap, va, &pa); (void) pmap_extract(pmap, va, &pa);
iommu_enter(dva, pa); iommu_enter(sc, dva, pa);
dva += pagesz; dva += pagesz;
va += pagesz; va += pagesz;
@ -694,6 +674,7 @@ iommu_dmamap_load_raw(t, map, segs, nsegs, size, flags)
bus_size_t size; bus_size_t size;
int flags; int flags;
{ {
struct iommu_softc *sc = t->_cookie;
struct vm_page *m; struct vm_page *m;
paddr_t pa; paddr_t pa;
bus_addr_t dva; bus_addr_t dva;
@ -705,7 +686,7 @@ iommu_dmamap_load_raw(t, map, segs, nsegs, size, flags)
map->dm_nsegs = 0; map->dm_nsegs = 0;
/* Allocate IOMMU resources */ /* Allocate IOMMU resources */
if ((error = iommu_dvma_alloc(map, segs[0]._ds_va, size, if ((error = iommu_dvma_alloc(sc, map, segs[0]._ds_va, size,
flags, &dva, &sgsize)) != 0) flags, &dva, &sgsize)) != 0)
return (error); return (error);
@ -727,7 +708,7 @@ iommu_dmamap_load_raw(t, map, segs, nsegs, size, flags)
if (sgsize == 0) if (sgsize == 0)
panic("iommu_dmamap_load_raw: size botch"); panic("iommu_dmamap_load_raw: size botch");
pa = VM_PAGE_TO_PHYS(m); pa = VM_PAGE_TO_PHYS(m);
iommu_enter(dva, pa); iommu_enter(sc, dva, pa);
dva += pagesz; dva += pagesz;
sgsize -= pagesz; sgsize -= pagesz;
} }
@ -746,6 +727,7 @@ iommu_dmamap_unload(t, map)
bus_dma_tag_t t; bus_dma_tag_t t;
bus_dmamap_t map; bus_dmamap_t map;
{ {
struct iommu_softc *sc = t->_cookie;
bus_dma_segment_t *segs = map->dm_segs; bus_dma_segment_t *segs = map->dm_segs;
int nsegs = map->dm_nsegs; int nsegs = map->dm_nsegs;
bus_addr_t dva; bus_addr_t dva;
@ -756,9 +738,9 @@ iommu_dmamap_unload(t, map)
dva = segs[i].ds_addr & -PAGE_SIZE; dva = segs[i].ds_addr & -PAGE_SIZE;
len = segs[i]._ds_sgsize; len = segs[i]._ds_sgsize;
iommu_remove(dva, len); iommu_remove(sc, dva, len);
s = splhigh(); s = splhigh();
error = extent_free(iommu_dvmamap, dva, len, EX_NOWAIT); error = extent_free(sc->sc_dvmamap, dva, len, EX_NOWAIT);
splx(s); splx(s);
if (error != 0) if (error != 0)
printf("warning: %ld of DVMA space lost\n", (long)len); printf("warning: %ld of DVMA space lost\n", (long)len);

View File

@ -1,4 +1,4 @@
/* $NetBSD: iommuvar.h,v 1.6 2002/08/23 02:53:12 thorpej Exp $ */ /* $NetBSD: iommuvar.h,v 1.7 2002/08/25 16:02:54 thorpej Exp $ */
/*- /*-
* Copyright (c) 1998 The NetBSD Foundation, Inc. * Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -50,7 +50,4 @@ struct iommu_attach_args {
int iom_nreg; int iom_nreg;
}; };
void iommu_enter __P((bus_addr_t, paddr_t));
void iommu_remove __P((bus_addr_t, bus_size_t));
#endif /* _IOMMU_VAR_H */ #endif /* _IOMMU_VAR_H */