diff options
Diffstat (limited to 'sys/arch/amd64/pci/agp_machdep.c')
-rw-r--r-- | sys/arch/amd64/pci/agp_machdep.c | 82 |
1 files changed, 77 insertions, 5 deletions
diff --git a/sys/arch/amd64/pci/agp_machdep.c b/sys/arch/amd64/pci/agp_machdep.c index ef7391845ba..5e320e95293 100644 --- a/sys/arch/amd64/pci/agp_machdep.c +++ b/sys/arch/amd64/pci/agp_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: agp_machdep.c,v 1.4 2009/06/06 06:02:44 oga Exp $ */ +/* $OpenBSD: agp_machdep.c,v 1.5 2010/04/08 01:26:44 oga Exp $ */ /* * Copyright (c) 2008 - 2009 Owain G. Ainsworth <oga@openbsd.org> @@ -54,6 +54,8 @@ #include <machine/cpufunc.h> #include <machine/bus.h> +#include <uvm/uvm.h> + #include "intagp.h" /* bus_dma functions */ @@ -69,6 +71,12 @@ agp_flush_cache(void) wbinvd(); } +void +agp_flush_cache_range(vaddr_t va, vsize_t sz) +{ + pmap_flush_cache(va, sz); +} + /* * functions for bus_dma used by drm for GEM * @@ -140,12 +148,21 @@ void agp_bus_dma_destroy(struct agp_softc *sc, bus_dma_tag_t dmat) { struct sg_cookie *cookie = dmat->_cookie; + bus_addr_t offset; /* * XXX clear up blocker queue */ + /* + * some backends use a dummy page to avoid errors on prefetching, etc. + * make sure that all of them are clean. + */ + for (offset = cookie->sg_ex->ex_start; + offset < cookie->sg_ex->ex_end; offset += PAGE_SIZE) + sc->sc_methods->unbind_page(sc->sc_chipc, offset); + sg_dmatag_destroy(cookie); free(dmat, M_DEVBUF); } @@ -157,7 +174,6 @@ agp_bus_dma_set_alignment(bus_dma_tag_t tag, bus_dmamap_t dmam, sg_dmamap_set_alignment(tag, dmam, alignment); } - /* * ick ick ick. However, the rest of this driver is supposedly MI (though * they only exist on x86), so this can't be in dev/pci. @@ -183,6 +199,12 @@ void intagp_dma_sync(bus_dma_tag_t tag, bus_dmamap_t dmam, bus_addr_t offset, bus_size_t size, int ops) { + bus_dma_segment_t *segp; + struct sg_page_map *spm; + void *addr; + paddr_t pa; + bus_addr_t poff, endoff, soff; + #ifdef DIAGNOSTIC if ((ops & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) != 0 && (ops & (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)) != 0) @@ -213,10 +235,60 @@ intagp_dma_sync(bus_dma_tag_t tag, bus_dmamap_t dmam, * The chipset also may need flushing, but that fits badly into * bus_dma and it done in the driver. */ + soff = trunc_page(offset); + endoff = round_page(offset + size); if (ops & BUS_DMASYNC_POSTREAD || ops & BUS_DMASYNC_PREREAD || ops & BUS_DMASYNC_PREWRITE) { - /* XXX use clflush */ - wbinvd(); + if (curcpu()->ci_cflushsz == 0) { + /* save some wbinvd()s. we're MD anyway so it's ok */ + wbinvd(); + return; + } + + mfence(); + spm = dmam->_dm_cookie; + switch (spm->spm_buftype) { + case BUS_BUFTYPE_LINEAR: + addr = spm->spm_origbuf + soff; + while (soff < endoff) { + pmap_flush_cache((vaddr_t)addr, PAGE_SIZE); + soff += PAGE_SIZE; + addr += PAGE_SIZE; + } break; + case BUS_BUFTYPE_RAW: + segp = (bus_dma_segment_t *)spm->spm_origbuf; + poff = 0; + + while (poff < soff) { + if (poff + segp->ds_len > soff) + break; + poff += segp->ds_len; + segp++; + } + /* first time round may not start at seg beginning */ + pa = segp->ds_addr + (soff - poff); + while (poff < endoff) { + for (; pa < segp->ds_addr + segp->ds_len && + poff < endoff; pa += PAGE_SIZE) { + pmap_flush_page(pa); + poff += PAGE_SIZE; + } + segp++; + if (poff < endoff) + pa = segp->ds_addr; + } + break; + /* You do not want to load mbufs or uios onto a graphics card */ + case BUS_BUFTYPE_MBUF: + /* FALLTHROUGH */ + case BUS_BUFTYPE_UIO: + /* FALLTHROUGH */ + default: + panic("intagp_dmamap_sync: bad buftype %d", + spm->spm_buftype); + + } + mfence(); } } -#endif +#endif /* NINTAGP > 0 */ |