diff options
author | Henric Jungheim <henric@cvs.openbsd.org> | 2003-03-06 08:26:09 +0000 |
---|---|---|
committer | Henric Jungheim <henric@cvs.openbsd.org> | 2003-03-06 08:26:09 +0000 |
commit | efca87016057d41201643e65d1f1c5d44716db0b (patch) | |
tree | 0a757cfc249bf077773a2182e04fd490183c3e6c /sys/arch/sparc64/dev/psycho.c | |
parent | 6216a22d89b680747bfb42b651aed1076b9dbf92 (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.c | 114 |
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); } |