summaryrefslogtreecommitdiff
path: root/sys/arch/amd64/pci/iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/amd64/pci/iommu.c')
-rw-r--r--sys/arch/amd64/pci/iommu.c394
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 */