diff options
Diffstat (limited to 'sys/arm/arm/busdma_machdep.c')
-rw-r--r-- | sys/arm/arm/busdma_machdep.c | 104 |
1 files changed, 23 insertions, 81 deletions
diff --git a/sys/arm/arm/busdma_machdep.c b/sys/arm/arm/busdma_machdep.c index 2540e15f75c5..44bc96bed734 100644 --- a/sys/arm/arm/busdma_machdep.c +++ b/sys/arm/arm/busdma_machdep.c @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2012-2015 Ian Lepore * Copyright (c) 2010 Mark Tinguely @@ -32,9 +32,6 @@ * From i386/busdma_machdep.c 191438 2009-04-23 20:24:19Z jhb */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -80,18 +77,14 @@ struct bounce_page; struct bounce_zone; struct bus_dma_tag { - bus_dma_tag_t parent; bus_size_t alignment; bus_addr_t boundary; bus_addr_t lowaddr; bus_addr_t highaddr; - bus_dma_filter_t *filter; - void *filterarg; bus_size_t maxsize; u_int nsegments; bus_size_t maxsegsz; int flags; - int ref_count; int map_count; bus_dma_lock_t *lockfunc; void *lockfuncarg; @@ -151,6 +144,7 @@ struct bus_dmamap { struct memdesc mem; bus_dmamap_callback_t *callback; void *callback_arg; + __sbintime_t queued_time; int flags; #define DMAMAP_COHERENT (1 << 0) #define DMAMAP_DMAMEM_ALLOC (1 << 1) @@ -175,6 +169,7 @@ MALLOC_DEFINE(M_BUSDMA, "busdma", "busdma metadata"); #define dmat_alignment(dmat) ((dmat)->alignment) #define dmat_flags(dmat) ((dmat)->flags) +#define dmat_highaddr(dmat) ((dmat)->highaddr) #define dmat_lowaddr(dmat) ((dmat)->lowaddr) #define dmat_lockfunc(dmat) ((dmat)->lockfunc) #define dmat_lockfuncarg(dmat) ((dmat)->lockfuncarg) @@ -245,7 +240,7 @@ SYSINIT(busdma, SI_SUB_KMEM+1, SI_ORDER_FIRST, busdma_init, NULL); * express, so we take a fast out. */ static int -exclusion_bounce_check(vm_offset_t lowaddr, vm_offset_t highaddr) +exclusion_bounce_check(bus_addr_t lowaddr, bus_addr_t highaddr) { int i; @@ -336,11 +331,7 @@ might_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t addr, * * Bouncing can be triggered by DMA that doesn't begin and end on cacheline * boundaries, or doesn't begin on an alignment boundary, or falls within the - * exclusion zone of any tag in the ancestry chain. - * - * For exclusions, walk the chain of tags comparing paddr to the exclusion zone - * within each tag. If the tag has a filter function, use it to decide whether - * the DMA needs to bounce, otherwise any DMA within the zone bounces. + * exclusion zone of the tag. */ static int must_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr, @@ -351,27 +342,11 @@ must_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr, return (1); /* - * The tag already contains ancestors' alignment restrictions so this - * check doesn't need to be inside the loop. + * Check the tag's exclusion zone. */ - if (alignment_bounce(dmat, paddr)) + if (exclusion_bounce(dmat) && addr_needs_bounce(dmat, paddr)) return (1); - /* - * Even though each tag has an exclusion zone that is a superset of its - * own and all its ancestors' exclusions, the exclusion zone of each tag - * up the chain must be checked within the loop, because the busdma - * rules say the filter function is called only when the address lies - * within the low-highaddr range of the tag that filterfunc belongs to. - */ - while (dmat != NULL && exclusion_bounce(dmat)) { - if ((paddr >= dmat->lowaddr && paddr <= dmat->highaddr) && - (dmat->filter == NULL || - dmat->filter(dmat->filterarg, paddr) != 0)) - return (1); - dmat = dmat->parent; - } - return (0); } @@ -400,6 +375,10 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, /* Return a NULL tag on failure */ *dmat = NULL; + /* Filters are no longer supported. */ + if (filter != NULL || filterarg != NULL) + return (EINVAL); + newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_BUSDMA, M_ZERO | M_NOWAIT); if (newtag == NULL) { @@ -408,19 +387,15 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, return (ENOMEM); } - newtag->parent = parent; newtag->alignment = alignment; newtag->boundary = boundary; newtag->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1); newtag->highaddr = trunc_page((vm_paddr_t)highaddr) + (PAGE_SIZE - 1); - newtag->filter = filter; - newtag->filterarg = filterarg; newtag->maxsize = maxsize; newtag->nsegments = nsegments; newtag->maxsegsz = maxsegsz; newtag->flags = flags; - newtag->ref_count = 1; /* Count ourself */ newtag->map_count = 0; if (lockfunc != NULL) { newtag->lockfunc = lockfunc; @@ -442,17 +417,6 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, else if (parent->boundary != 0) newtag->boundary = MIN(parent->boundary, newtag->boundary); - if (newtag->filter == NULL) { - /* - * Short circuit to looking at our parent directly - * since we have encapsulated all of its information - */ - newtag->filter = parent->filter; - newtag->filterarg = parent->filterarg; - newtag->parent = parent->parent; - } - if (newtag->parent != NULL) - atomic_add_int(&parent->ref_count, 1); } if (exclusion_bounce_check(newtag->lowaddr, newtag->highaddr)) @@ -512,7 +476,6 @@ bus_dma_template_clone(bus_dma_template_t *t, bus_dma_tag_t dmat) if (t == NULL || dmat == NULL) return; - t->parent = dmat->parent; t->alignment = dmat->alignment; t->boundary = dmat->boundary; t->lowaddr = dmat->lowaddr; @@ -535,39 +498,17 @@ bus_dma_tag_set_domain(bus_dma_tag_t dmat, int domain) int bus_dma_tag_destroy(bus_dma_tag_t dmat) { -#ifdef KTR - bus_dma_tag_t dmat_copy = dmat; -#endif - int error; - - error = 0; + int error = 0; if (dmat != NULL) { if (dmat->map_count != 0) { error = EBUSY; goto out; } - - while (dmat != NULL) { - bus_dma_tag_t parent; - - parent = dmat->parent; - atomic_subtract_int(&dmat->ref_count, 1); - if (dmat->ref_count == 0) { - atomic_subtract_32(&tags_total, 1); - free(dmat, M_BUSDMA); - /* - * Last reference count, so - * release our reference - * count on our parent. - */ - dmat = parent; - } else - dmat = NULL; - } + free(dmat, M_BUSDMA); } out: - CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error); + CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat, error); return (error); } @@ -776,10 +717,10 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags, howmany(dmat->maxsize, MIN(dmat->maxsegsz, PAGE_SIZE)) && dmat->alignment <= PAGE_SIZE && (dmat->boundary % PAGE_SIZE) == 0) { - *vaddr = (void *)kmem_alloc_attr(dmat->maxsize, mflags, 0, + *vaddr = kmem_alloc_attr(dmat->maxsize, mflags, 0, dmat->lowaddr, memattr); } else { - *vaddr = (void *)kmem_alloc_contig(dmat->maxsize, mflags, 0, + *vaddr = kmem_alloc_contig(dmat->maxsize, mflags, 0, dmat->lowaddr, dmat->alignment, dmat->boundary, memattr); } if (*vaddr == NULL) { @@ -822,7 +763,7 @@ bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) !exclusion_bounce(dmat)) uma_zfree(bufzone->umazone, vaddr); else - kmem_free((vm_offset_t)vaddr, dmat->maxsize); + kmem_free(vaddr, dmat->maxsize); dmat->map_count--; if (map->flags & DMAMAP_COHERENT) @@ -871,6 +812,7 @@ _bus_dmamap_count_pages(bus_dma_tag_t dmat, pmap_t pmap, bus_dmamap_t map, vm_offset_t vaddr; vm_offset_t vendaddr; bus_addr_t paddr; + bus_size_t sg_len; if (map->pagesneeded == 0) { CTR5(KTR_BUSDMA, "lowaddr= %d, boundary= %d, alignment= %d" @@ -885,16 +827,16 @@ _bus_dmamap_count_pages(bus_dma_tag_t dmat, pmap_t pmap, bus_dmamap_t map, vendaddr = (vm_offset_t)buf + buflen; while (vaddr < vendaddr) { + sg_len = MIN(vendaddr - vaddr, + (PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK))); + sg_len = MIN(sg_len, dmat->maxsegsz); if (__predict_true(pmap == kernel_pmap)) paddr = pmap_kextract(vaddr); else paddr = pmap_extract(pmap, vaddr); - if (must_bounce(dmat, map, paddr, - min(vendaddr - vaddr, (PAGE_SIZE - ((vm_offset_t)vaddr & - PAGE_MASK)))) != 0) { + if (must_bounce(dmat, map, paddr, sg_len) != 0) map->pagesneeded++; - } - vaddr += (PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK)); + vaddr += sg_len; } CTR1(KTR_BUSDMA, "pagesneeded= %d", map->pagesneeded); } |