diff options
Diffstat (limited to 'sys/arch/amd64/pci/iommu.c')
-rw-r--r-- | sys/arch/amd64/pci/iommu.c | 394 |
1 files changed, 69 insertions, 325 deletions
diff --git a/sys/arch/amd64/pci/iommu.c b/sys/arch/amd64/pci/iommu.c index 18c11bbf21d..50eeb79493b 100644 --- a/sys/arch/amd64/pci/iommu.c +++ b/sys/arch/amd64/pci/iommu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iommu.c,v 1.27 2009/04/15 23:53:22 oga Exp $ */ +/* $OpenBSD: iommu.c,v 1.28 2009/04/21 17:05:29 oga Exp $ */ /* * Copyright (c) 2005 Jason L. Wright (jason@thought.net) @@ -33,7 +33,6 @@ #include <sys/errno.h> #include <sys/device.h> #include <sys/lock.h> -#include <sys/extent.h> #include <sys/malloc.h> #include <uvm/uvm_extern.h> @@ -100,14 +99,12 @@ #define IOMMU_SIZE 512 /* size in MB */ #define IOMMU_ALIGN IOMMU_SIZE -extern paddr_t avail_end; -extern struct extent *iomem_ex; - int amdgart_enable = 0; +#ifndef SMALL_KERNEL /* no bigmem in ramdisks */ + struct amdgart_softc { pci_chipset_tag_t g_pc; - struct extent *g_ex; paddr_t g_pa; paddr_t g_scribpa; void *g_scrib; @@ -118,58 +115,56 @@ struct amdgart_softc { pcitag_t g_tags[1]; }; -void amdgart_invalidate_wait(struct amdgart_softc *); -void amdgart_invalidate(struct amdgart_softc *); -void amdgart_probe(struct pcibus_attach_args *); -void amdgart_dumpregs(struct amdgart_softc *); -int amdgart_iommu_map(struct amdgart_softc *, bus_dmamap_t, - bus_dma_segment_t *); -int amdgart_iommu_unmap(struct amdgart_softc *, bus_dma_segment_t *); -int amdgart_reload(struct amdgart_softc *, bus_dmamap_t); -int amdgart_ok(pci_chipset_tag_t, pcitag_t); -int amdgart_enabled(pci_chipset_tag_t, pcitag_t); -void amdgart_initpt(struct amdgart_softc *, u_long); - -int amdgart_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t, - bus_size_t, int, bus_dmamap_t *); -void amdgart_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t); -int amdgart_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, - struct proc *, int); -int amdgart_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *, int); -int amdgart_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, struct uio *, int); -int amdgart_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, - bus_dma_segment_t *, int, bus_size_t, int); -void amdgart_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); -void amdgart_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, - bus_size_t, int); - -int amdgart_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, bus_size_t, - bus_dma_segment_t *, int, int *, int); -void amdgart_dmamem_free(bus_dma_tag_t, bus_dma_segment_t *, int); -int amdgart_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *, int, size_t, - caddr_t *, int); -void amdgart_dmamem_unmap(bus_dma_tag_t, caddr_t, size_t); -paddr_t amdgart_dmamem_mmap(bus_dma_tag_t, bus_dma_segment_t *, int, off_t, - int, int); +void amdgart_probe(struct pcibus_attach_args *); +void amdgart_dumpregs(struct amdgart_softc *); +int amdgart_ok(pci_chipset_tag_t, pcitag_t); +int amdgart_enabled(pci_chipset_tag_t, pcitag_t); +void amdgart_initpt(struct amdgart_softc *, u_long); +void amdgart_bind_page(void *, vaddr_t, paddr_t, int); +void amdgart_unbind_page(void *, vaddr_t); +void amdgart_invalidate(void *); +void amdgart_invalidate_wait(struct amdgart_softc *); struct bus_dma_tag amdgart_bus_dma_tag = { NULL, /* _may_bounce */ - amdgart_dmamap_create, - amdgart_dmamap_destroy, - amdgart_dmamap_load, - amdgart_dmamap_load_mbuf, - amdgart_dmamap_load_uio, - amdgart_dmamap_load_raw, - amdgart_dmamap_unload, + sg_dmamap_create, + sg_dmamap_destroy, + sg_dmamap_load, + sg_dmamap_load_mbuf, + sg_dmamap_load_uio, + sg_dmamap_load_raw, + sg_dmamap_unload, NULL, - amdgart_dmamem_alloc, - amdgart_dmamem_free, - amdgart_dmamem_map, - amdgart_dmamem_unmap, - amdgart_dmamem_mmap, + sg_dmamem_alloc, + _bus_dmamem_free, + _bus_dmamem_map, + _bus_dmamem_unmap, + _bus_dmamem_mmap, }; void +amdgart_bind_page(void *handle, vaddr_t offset, paddr_t page, int flags) +{ + struct amdgart_softc *sc = handle; + u_int32_t pgno, pte; + + pgno = (offset - sc->g_pa) >> PGSHIFT; + pte = GART_PTE_VALID | GART_PTE_COHERENT | + ((page >> 28) & GART_PTE_PHYSHI) | (page & GART_PTE_PHYSLO); + sc->g_pte[pgno] = pte; +} + +void +amdgart_unbind_page(void *handle, vaddr_t offset) +{ + struct amdgart_softc *sc = handle; + u_int32_t pgno; + + pgno = (offset - sc->g_pa) >> PGSHIFT; + sc->g_pte[pgno] = sc->g_scribpte; +} + +void amdgart_invalidate_wait(struct amdgart_softc *sc) { int i, n; @@ -187,8 +182,9 @@ amdgart_invalidate_wait(struct amdgart_softc *sc) } void -amdgart_invalidate(struct amdgart_softc *sc) +amdgart_invalidate(void* handle) { + struct amdgart_softc *sc = handle; int n; for (n = 0; n < sc->g_count; n++) @@ -257,16 +253,16 @@ static const struct gart_size { void amdgart_probe(struct pcibus_attach_args *pba) { - struct amdgart_softc *sc; - int dev, count = 0, encount = 0, r, nseg; - u_long mapsize, ptesize, gartsize = 0; - bus_dma_segment_t seg; - pcitag_t tag; - pcireg_t v; - paddr_t pa; - void *scrib = NULL; - u_int32_t *pte = NULL; - paddr_t ptepa; + struct amdgart_softc *sc; + struct sg_cookie *cookie = NULL; + void *scrib = NULL; + u_int32_t *pte; + int dev, count = 0, encount = 0, r, nseg; + u_long mapsize, ptesize, gartsize = 0; + bus_dma_segment_t seg; + pcitag_t tag; + pcireg_t v; + paddr_t pa, ptepa; if (amdgart_enable == 0) return; @@ -355,13 +351,6 @@ amdgart_probe(struct pcibus_attach_args *pba) } ptepa = seg.ds_addr; - sc->g_ex = extent_create("iommu", sc->g_pa, sc->g_pa + mapsize - 1, - M_DEVBUF, NULL, NULL, EX_NOWAIT | EX_NOCOALESCE); - if (sc->g_ex == NULL) { - printf("\nGART: extent create failed"); - goto err; - } - scrib = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); if (scrib == NULL) { printf("\nGART: didn't get scribble page"); @@ -377,6 +366,13 @@ amdgart_probe(struct pcibus_attach_args *pba) sc->g_pte = pte; sc->g_dmat = pba->pba_dmat; + if ((cookie = sg_dmatag_init("iommu", sc, sc->g_pa, mapsize, + amdgart_bind_page, amdgart_unbind_page, + amdgart_invalidate)) == NULL) { + printf("\nGART: didn't get dma cookie\n"); + goto err; + } + for (count = 0, dev = 24; dev < 32; dev++) { tag = pci_make_tag(pba->pba_pc, 0, dev, 3); @@ -436,7 +432,7 @@ amdgart_probe(struct pcibus_attach_args *pba) amdgart_initpt(sc, ptesize / sizeof(*sc->g_pte)); sc->g_count = count; - amdgart_bus_dma_tag._cookie = sc; + amdgart_bus_dma_tag._cookie = cookie; pba->pba_dmat = &amdgart_bus_dma_tag; return; @@ -444,10 +440,10 @@ amdgart_probe(struct pcibus_attach_args *pba) err: _bus_dmamem_free(pba->pba_dmat, &seg, 1); nofreeseg: - if (sc->g_ex != NULL) - extent_destroy(sc->g_ex); if (scrib != NULL) free(scrib, M_DEVBUF); + if (cookie != NULL) + sg_dmatag_destroy(cookie); if (sc != NULL) free(sc, M_DEVBUF); } @@ -462,256 +458,4 @@ amdgart_initpt(struct amdgart_softc *sc, u_long nent) amdgart_invalidate(sc); } -int -amdgart_reload(struct amdgart_softc *sc, bus_dmamap_t dmam) -{ - int i, j, err; - - for (i = 0; i < dmam->dm_nsegs; i++) { - psize_t len; - - len = dmam->dm_segs[i].ds_len; - err = amdgart_iommu_map(sc, dmam, &dmam->dm_segs[i]); - if (err) { - for (j = 0; j < i - 1; j++) - amdgart_iommu_unmap(sc, &dmam->dm_segs[j]); - return (err); - } - } - return (0); -} - -int -amdgart_iommu_map(struct amdgart_softc *sc, bus_dmamap_t dmam, - bus_dma_segment_t *seg) -{ - paddr_t base, end, idx; - psize_t alen; - u_long res; - int err, s; - u_int32_t pgno, flags; - - base = trunc_page(seg->ds_addr); - end = roundup(seg->ds_addr + seg->ds_len, PAGE_SIZE); - alen = end - base; - - s = splhigh(); - err = extent_alloc(sc->g_ex, alen, PAGE_SIZE, 0, dmam->_dm_boundary, - EX_NOWAIT, &res); - splx(s); - if (err) { - printf("GART: extent_alloc %d\n", err); - return (err); - } - - seg->ds_addr = res | (seg->ds_addr & PGOFSET); - - for (idx = 0; idx < alen; idx += PAGE_SIZE) { - pgno = ((res + idx) - sc->g_pa) >> PGSHIFT; - flags = GART_PTE_VALID | GART_PTE_COHERENT | - (((base + idx) >> 28) & GART_PTE_PHYSHI) | - ((base + idx) & GART_PTE_PHYSLO); - sc->g_pte[pgno] = flags; - } - - return (0); -} - -int -amdgart_iommu_unmap(struct amdgart_softc *sc, bus_dma_segment_t *seg) -{ - paddr_t base, end, idx; - psize_t alen; - int err, s; - u_int32_t pgno; - - base = trunc_page(seg->ds_addr); - end = roundup(seg->ds_addr + seg->ds_len, PAGE_SIZE); - alen = end - base; - - /* - * order is significant here; invalidate the iommu page table - * entries, then mark them as freed in the extent. - */ - - for (idx = 0; idx < alen; idx += PAGE_SIZE) { - pgno = ((base - sc->g_pa) + idx) >> PGSHIFT; - sc->g_pte[pgno] = sc->g_scribpte; - } - - s = splhigh(); - err = extent_free(sc->g_ex, base, alen, EX_NOWAIT); - splx(s); - if (err) { - /* XXX Shouldn't happen, but if it does, I think we lose. */ - printf("GART: extent_free %d\n", err); - return (err); - } - - return (0); -} - -int -amdgart_dmamap_create(bus_dma_tag_t tag, bus_size_t size, int nsegments, - bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) -{ - struct amdgart_softc *sc = tag->_cookie; - - return (bus_dmamap_create(sc->g_dmat, size, nsegments, - maxsegsz, boundary, flags, dmamp)); -} - -void -amdgart_dmamap_destroy(bus_dma_tag_t tag, bus_dmamap_t dmam) -{ - struct amdgart_softc *sc = tag->_cookie; - - bus_dmamap_destroy(sc->g_dmat, dmam); -} - -int -amdgart_dmamap_load(bus_dma_tag_t tag, bus_dmamap_t dmam, void *buf, - bus_size_t buflen, struct proc *p, int flags) -{ - struct amdgart_softc *sc = tag->_cookie; - int err; - - err = bus_dmamap_load(sc->g_dmat, dmam, buf, buflen, - p, flags); - if (err) - return (err); - err = amdgart_reload(sc, dmam); - if (err) - bus_dmamap_unload(sc->g_dmat, dmam); - else - amdgart_invalidate(sc); - return (err); -} - -int -amdgart_dmamap_load_mbuf(bus_dma_tag_t tag, bus_dmamap_t dmam, - struct mbuf *chain, int flags) -{ - struct amdgart_softc *sc = tag->_cookie; - int err; - - err = bus_dmamap_load_mbuf(sc->g_dmat, dmam, - chain, flags); - if (err) - return (err); - err = amdgart_reload(sc, dmam); - if (err) - bus_dmamap_unload(sc->g_dmat, dmam); - else - amdgart_invalidate(sc); - return (err); -} - -int -amdgart_dmamap_load_uio(bus_dma_tag_t tag, bus_dmamap_t dmam, - struct uio *uio, int flags) -{ - struct amdgart_softc *sc = tag->_cookie; - int err; - - err = bus_dmamap_load_uio(sc->g_dmat, dmam, uio, flags); - if (err) - return (err); - err = amdgart_reload(sc, dmam); - if (err) - bus_dmamap_unload(sc->g_dmat, dmam); - else - amdgart_invalidate(sc); - return (err); -} - -int -amdgart_dmamap_load_raw(bus_dma_tag_t tag, bus_dmamap_t dmam, - bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) -{ - struct amdgart_softc *sc = tag->_cookie; - int err; - - err = bus_dmamap_load_raw(sc->g_dmat, dmam, segs, nsegs, - size, flags); - if (err) - return (err); - err = amdgart_reload(sc, dmam); - if (err) - bus_dmamap_unload(sc->g_dmat, dmam); - else - amdgart_invalidate(sc); - return (err); -} - -void -amdgart_dmamap_unload(bus_dma_tag_t tag, bus_dmamap_t dmam) -{ - struct amdgart_softc *sc = tag->_cookie; - int i; - - for (i = 0; i < dmam->dm_nsegs; i++) - amdgart_iommu_unmap(sc, &dmam->dm_segs[i]); - amdgart_invalidate(sc); - bus_dmamap_unload(sc->g_dmat, dmam); -} - -void -amdgart_dmamap_sync(bus_dma_tag_t tag, bus_dmamap_t dmam, bus_addr_t offset, - bus_size_t size, int ops) -{ - struct amdgart_softc *sc = tag->_cookie; - - /* - * XXX how do we deal with non-coherent mappings? We don't - * XXX allow them right now. - */ - bus_dmamap_sync(sc->g_dmat, dmam, offset, size, ops); -} - -int -amdgart_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size, bus_size_t alignment, - bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, - int flags) -{ - struct amdgart_softc *sc = tag->_cookie; - - return (bus_dmamem_alloc(sc->g_dmat, size, alignment, - boundary, segs, nsegs, rsegs, flags)); -} - -void -amdgart_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs) -{ - struct amdgart_softc *sc = tag->_cookie; - - bus_dmamem_free(sc->g_dmat, segs, nsegs); -} - -int -amdgart_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs, - size_t size, caddr_t *kvap, int flags) -{ - struct amdgart_softc *sc = tag->_cookie; - - return (bus_dmamem_map(sc->g_dmat, segs, nsegs, size, - kvap, flags)); -} - -void -amdgart_dmamem_unmap(bus_dma_tag_t tag, caddr_t kva, size_t size) -{ - struct amdgart_softc *sc = tag->_cookie; - - bus_dmamem_unmap(sc->g_dmat, kva, size); -} - -paddr_t -amdgart_dmamem_mmap(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs, - off_t off, int prot, int flags) -{ - struct amdgart_softc *sc = tag->_cookie; - - return (bus_dmamem_mmap(sc->g_dmat, segs, nsegs, off, - prot, flags)); -} +#endif /* !SMALL_KERNEL */ |