summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64/dev/psycho.c
diff options
context:
space:
mode:
authorHenric Jungheim <henric@cvs.openbsd.org>2003-03-06 08:26:09 +0000
committerHenric Jungheim <henric@cvs.openbsd.org>2003-03-06 08:26:09 +0000
commitefca87016057d41201643e65d1f1c5d44716db0b (patch)
tree0a757cfc249bf077773a2182e04fd490183c3e6c /sys/arch/sparc64/dev/psycho.c
parent6216a22d89b680747bfb42b651aed1076b9dbf92 (diff)
The existing IOMMU code had a rounding problem that was most noticeable
on faster systems under heavy network load. This replaces some of the unreadable iommu functions with something a little less dense and a lot less crash prone. The bus_dma function pointer/cookie handling was broken. Change them to work like the stacked bus_space drivers (where "work" is the key word). Tested my many (thanks). ok jason@ deraadt@
Diffstat (limited to 'sys/arch/sparc64/dev/psycho.c')
-rw-r--r--sys/arch/sparc64/dev/psycho.c114
1 files changed, 75 insertions, 39 deletions
diff --git a/sys/arch/sparc64/dev/psycho.c b/sys/arch/sparc64/dev/psycho.c
index a5bdd7abdfc..98a4ce8c10f 100644
--- a/sys/arch/sparc64/dev/psycho.c
+++ b/sys/arch/sparc64/dev/psycho.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: psycho.c,v 1.28 2003/03/05 00:20:13 henric Exp $ */
+/* $OpenBSD: psycho.c,v 1.29 2003/03/06 08:26:08 henric Exp $ */
/* $NetBSD: psycho.c,v 1.39 2001/10/07 20:30:41 eeh Exp $ */
/*
@@ -101,19 +101,22 @@ int _psycho_bus_map(bus_space_tag_t, bus_space_tag_t, bus_addr_t,
void *psycho_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int,
int (*)(void *), void *);
-int psycho_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *,
+int psycho_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, bus_size_t, int, bus_size_t,
+ bus_size_t, int, bus_dmamap_t *);
+void psycho_dvmamap_destroy(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t);
+int psycho_dmamap_load(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t, void *,
bus_size_t, struct proc *, int);
-void psycho_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
-int psycho_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
+void psycho_dmamap_unload(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t);
+int psycho_dmamap_load_raw(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t,
bus_dma_segment_t *, int, bus_size_t, int);
-void psycho_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
+void psycho_dmamap_sync(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
bus_size_t, int);
-int psycho_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, bus_size_t,
+int psycho_dmamem_alloc(bus_dma_tag_t, bus_dma_tag_t, bus_size_t, bus_size_t, bus_size_t,
bus_dma_segment_t *, int, int *, int);
-void psycho_dmamem_free(bus_dma_tag_t, bus_dma_segment_t *, int);
-int psycho_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *, int, size_t,
+void psycho_dmamem_free(bus_dma_tag_t, bus_dma_tag_t, bus_dma_segment_t *, int);
+int psycho_dmamem_map(bus_dma_tag_t, bus_dma_tag_t, bus_dma_segment_t *, int, size_t,
caddr_t *, int);
-void psycho_dmamem_unmap(bus_dma_tag_t, caddr_t, size_t);
+void psycho_dmamem_unmap(bus_dma_tag_t, bus_dma_tag_t, caddr_t, size_t);
void psycho_map_psycho(struct psycho_softc *, int, bus_addr_t, bus_size_t,
bus_addr_t, bus_size_t);
@@ -471,6 +474,7 @@ psycho_attach(struct device *parent, struct device *self, void *aux)
offsetof(struct pci_ctl, pci_strbuf),
sizeof(struct iommu_strbuf),
&sb->sb_sb)) {
+ printf("STC0 subregion failed\n");
sb->sb_flush = 0;
}
@@ -507,12 +511,14 @@ psycho_attach(struct device *parent, struct device *self, void *aux)
offsetof(struct pci_ctl, pci_strbuf),
sizeof(struct iommu_strbuf),
&sb->sb_sb)) {
+ printf("STC1 subregion failed\n");
sb->sb_flush = 0;
}
/* Point out iommu at the strbuf_ctl. */
sc->sc_is->is_sb[1] = sb;
}
+
iommu_reset(sc->sc_is);
}
@@ -661,9 +667,12 @@ psycho_ue(void *arg)
/*
* It's uncorrectable. Dump the regs and panic.
*/
- panic("%s: uncorrectable DMA error AFAR %llx (pa=%llx) AFSR %llx",
- sc->sc_dev.dv_xname, afar,
- (long long)iommu_extract(sc->sc_is, (vaddr_t)afar), afsr);
+ panic("%s: uncorrectable DMA error AFAR %llx (pa=%llx tte=%llx/%llx) "
+ "AFSR %llx", sc->sc_dev.dv_xname, afar,
+ iommu_extract(sc->sc_is, (vaddr_t)afar),
+ iommu_lookup_tte(sc->sc_is, (vaddr_t)afar),
+ iommu_fetch_tte(sc->sc_is, (paddr_t)afar),
+ afsr);
return (1);
}
@@ -875,12 +884,9 @@ psycho_alloc_dma_tag(struct psycho_pbm *pp)
bzero(dt, sizeof *dt);
dt->_cookie = pp;
dt->_parent = pdt;
-#define PCOPY(x) dt->x = pdt->x
- PCOPY(_dmamap_create);
- PCOPY(_dmamap_destroy);
+ dt->_dmamap_create = psycho_dmamap_create;
+ dt->_dmamap_destroy = psycho_dvmamap_destroy;
dt->_dmamap_load = psycho_dmamap_load;
- PCOPY(_dmamap_load_mbuf);
- PCOPY(_dmamap_load_uio);
dt->_dmamap_load_raw = psycho_dmamap_load_raw;
dt->_dmamap_unload = psycho_dmamap_unload;
dt->_dmamap_sync = psycho_dmamap_sync;
@@ -888,8 +894,6 @@ psycho_alloc_dma_tag(struct psycho_pbm *pp)
dt->_dmamem_free = psycho_dmamem_free;
dt->_dmamem_map = psycho_dmamem_map;
dt->_dmamem_unmap = psycho_dmamem_unmap;
- PCOPY(_dmamem_mmap);
-#undef PCOPY
return (dt);
}
@@ -1117,92 +1121,124 @@ psycho_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
* hooks into the iommu dvma calls.
*/
int
-psycho_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
- bus_size_t buflen, struct proc *p, int flags)
+psycho_dmamap_create(bus_dma_tag_t t, bus_dma_tag_t t0, bus_size_t size,
+ int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags,
+ bus_dmamap_t *dmamp)
+{
+ struct psycho_pbm *pp = t->_cookie;
+ struct psycho_softc *sc = pp->pp_sc;
+
+ return (iommu_dvmamap_create(t0, sc->sc_is, &pp->pp_sb, size,
+ nsegments, maxsegsz, boundary, flags, dmamp));
+}
+
+void
+psycho_dvmamap_destroy(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map)
+{
+ iommu_dvmamap_destroy(t0, map);
+}
+
+int
+psycho_dmamap_load(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map,
+ void *buf, bus_size_t buflen, struct proc *p, int flags)
{
struct psycho_pbm *pp = t->_cookie;
struct psycho_softc *sc = pp->pp_sc;
- return (iommu_dvmamap_load(t, sc->sc_is, map, buf, buflen, p, flags));
+ if (pp->pp_sb.sb_flush == NULL)
+ flags &= ~BUS_DMA_STREAMING;
+
+ return (iommu_dvmamap_load(t0, sc->sc_is, map, buf, buflen, p, flags));
}
void
-psycho_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
+psycho_dmamap_unload(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map)
{
struct psycho_pbm *pp = t->_cookie;
struct psycho_softc *sc = pp->pp_sc;
- iommu_dvmamap_unload(t, sc->sc_is, map);
+ iommu_dvmamap_unload(t0, sc->sc_is, map);
}
int
-psycho_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
+psycho_dmamap_load_raw(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map,
bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
{
struct psycho_pbm *pp = t->_cookie;
struct psycho_softc *sc = pp->pp_sc;
- return (iommu_dvmamap_load_raw(t, sc->sc_is, map, segs, nsegs, flags,
+ if (pp->pp_sb.sb_flush == NULL)
+ flags &= ~BUS_DMA_STREAMING;
+
+ return (iommu_dvmamap_load_raw(t0, sc->sc_is, map, segs, nsegs, flags,
size));
}
void
-psycho_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
+psycho_dmamap_sync(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dmamap_t map, bus_addr_t offset,
bus_size_t len, int ops)
{
struct psycho_pbm *pp = t->_cookie;
struct psycho_softc *sc = pp->pp_sc;
+ if (t->_parent == NULL)
+ panic("psycho_dmamap_sync: no parent");
+
+ for (t = t->_parent; t->_dmamap_sync == NULL; t = t->_parent)
+ if (t == NULL)
+ panic("psycho_dmamap_sync: can't find implementation");
+
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);
+ (*t->_dmamap_sync)(t, t0, map, offset, len,
+ ops);
+ iommu_dvmamap_sync(t0, 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);
+ iommu_dvmamap_sync(t0, sc->sc_is, map, offset, len, ops);
+ (*t->_dmamap_sync)(t, t0, map, offset, len, ops);
}
}
int
-psycho_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
+psycho_dmamem_alloc(bus_dma_tag_t t, bus_dma_tag_t t0, bus_size_t size, bus_size_t alignment,
bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
int flags)
{
struct psycho_pbm *pp = t->_cookie;
struct psycho_softc *sc = pp->pp_sc;
- return (iommu_dvmamem_alloc(t, sc->sc_is, size, alignment, boundary,
+ return (iommu_dvmamem_alloc(t0, sc->sc_is, size, alignment, boundary,
segs, nsegs, rsegs, flags));
}
void
-psycho_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs)
+psycho_dmamem_free(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dma_segment_t *segs, int nsegs)
{
struct psycho_pbm *pp = t->_cookie;
struct psycho_softc *sc = pp->pp_sc;
- iommu_dvmamem_free(t, sc->sc_is, segs, nsegs);
+ iommu_dvmamem_free(t0, sc->sc_is, segs, nsegs);
}
int
-psycho_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
+psycho_dmamem_map(bus_dma_tag_t t, bus_dma_tag_t t0, bus_dma_segment_t *segs, int nsegs,
size_t size, caddr_t *kvap, int flags)
{
struct psycho_pbm *pp = t->_cookie;
struct psycho_softc *sc = pp->pp_sc;
return (iommu_dvmamem_map
- (t, sc->sc_is, segs, nsegs, size, kvap, flags));
+ (t0, sc->sc_is, segs, nsegs, size, kvap, flags));
}
void
-psycho_dmamem_unmap(bus_dma_tag_t t, caddr_t kva, size_t size)
+psycho_dmamem_unmap(bus_dma_tag_t t, bus_dma_tag_t t0, caddr_t kva, size_t size)
{
struct psycho_pbm *pp = t->_cookie;
struct psycho_softc *sc = pp->pp_sc;
- iommu_dvmamem_unmap(t, sc->sc_is, kva, size);
+ iommu_dvmamem_unmap(t0, sc->sc_is, kva, size);
}