FreeBSD/sys/mips/mips/busdma_machdep.c
/*
 * Allocate a piece of memory that can be efficiently mapped into
 * bus device space based on the constraints lited in the dma tag.
 * A dmamap to for use with dmamap_load is also allocated.
 */
Allocate a piece of memory that can be efficiently mapped into
bus device space based on the constraints lited in the dma tag.
A dmamap to for use with dmamap_load is also allocated.
Allocate a piece of memory that can be efficiently mapped into bus device space based on the constraints lited in the dma tag . A dmamap to for use with dmamap_load is also allocated .
int
bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddrp, int flags,
    bus_dmamap_t *mapp)
{
	bus_dmamap_t newmap = NULL;
	busdma_bufalloc_t ba;
	struct busdma_bufzone *bufzone;
	vm_memattr_t memattr;
	void *vaddr;
	int mflags;
	if (flags & BUS_DMA_NOWAIT)
		mflags = M_NOWAIT;
	else
		mflags = M_WAITOK;
	if (dmat->segments == NULL) {
		dmat->segments = (bus_dma_segment_t *)malloc(
		    sizeof(bus_dma_segment_t) * dmat->nsegments, M_BUSDMA,
		    mflags);
		if (dmat->segments == NULL) {
			CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
			    __func__, dmat, dmat->flags, ENOMEM);
			return (ENOMEM);
		}
	}
	newmap = _busdma_alloc_dmamap(dmat);
	if (newmap == NULL) {
		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
		    __func__, dmat, dmat->flags, ENOMEM);
		return (ENOMEM);
	}
	if (dmat->flags & BUS_DMA_COHERENT)
	    flags &= ~BUS_DMA_COHERENT;
	if (flags & BUS_DMA_COHERENT) {
		memattr = VM_MEMATTR_UNCACHEABLE;
		ba = coherent_allocator;
		newmap->flags |= DMAMAP_UNCACHEABLE;
	} else {
		memattr = VM_MEMATTR_DEFAULT;
		ba = standard_allocator;
	}
	newmap->flags |= DMAMAP_CACHE_ALIGNED;
	if (flags & BUS_DMA_ZERO)
		mflags |= M_ZERO;
	bufzone = busdma_bufalloc_findzone(ba, dmat->maxsize);
	if (bufzone != NULL && dmat->alignment <= bufzone->size &&
	    !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr)) {
		vaddr = uma_zalloc(bufzone->umazone, mflags);
	} else if (dmat->nsegments >= btoc(dmat->maxsize) &&
	    dmat->alignment <= PAGE_SIZE && dmat->boundary == 0) {
		vaddr = (void *)kmem_alloc_attr(kernel_arena, dmat->maxsize,
		    mflags, 0, dmat->lowaddr, memattr);
	} else {
		vaddr = (void *)kmem_alloc_contig(kernel_arena, dmat->maxsize,
		    mflags, 0, dmat->lowaddr, dmat->alignment, dmat->boundary,
		    memattr);
	}
	if (vaddr == NULL) {
		_busdma_free_dmamap(newmap);
		newmap = NULL;
	} else {
		newmap->sync_count = 0;
	}
	*vaddrp = vaddr;
	*mapp = newmap;
	return (vaddr == NULL ? ENOMEM : 0);
}
int bus_dmamem_alloc ( bus_dma_tag_t dmat , void * * vaddrp , int flags , bus_dmamap_t * mapp ) { bus_dmamap_t newmap = NULL ; busdma_bufalloc_t ba ; struct busdma_bufzone * bufzone ; vm_memattr_t memattr ; void * vaddr ; int mflags ; if ( flags & BUS_DMA_NOWAIT ) mflags = M_NOWAIT ; else mflags = M_WAITOK ; if ( dmat -> segments == NULL ) { dmat -> segments = ( bus_dma_segment_t * ) malloc ( sizeof ( bus_dma_segment_t ) * dmat -> nsegments , M_BUSDMA , mflags ) ; if ( dmat -> segments == NULL ) { CTR4 ( KTR_BUSDMA , " " , __func__ , dmat , dmat -> flags , ENOMEM ) ; return ( ENOMEM ) ; } } newmap = _busdma_alloc_dmamap ( dmat ) ; if ( newmap == NULL ) { CTR4 ( KTR_BUSDMA , " " , __func__ , dmat , dmat -> flags , ENOMEM ) ; return ( ENOMEM ) ; } if ( dmat -> flags & BUS_DMA_COHERENT ) flags &= ~ BUS_DMA_COHERENT ; if ( flags & BUS_DMA_COHERENT ) { memattr = VM_MEMATTR_UNCACHEABLE ; ba = coherent_allocator ; newmap -> flags |= DMAMAP_UNCACHEABLE ; } else { memattr = VM_MEMATTR_DEFAULT ; ba = standard_allocator ; } newmap -> flags |= DMAMAP_CACHE_ALIGNED ; if ( flags & BUS_DMA_ZERO ) mflags |= M_ZERO ; bufzone = busdma_bufalloc_findzone ( ba , dmat -> maxsize ) ; if ( bufzone != NULL && dmat -> alignment <= bufzone -> size && ! _bus_dma_can_bounce ( dmat -> lowaddr , dmat -> highaddr ) ) { vaddr = uma_zalloc ( bufzone -> umazone , mflags ) ; } else if ( dmat -> nsegments >= btoc ( dmat -> maxsize ) && dmat -> alignment <= PAGE_SIZE && dmat -> boundary == 0 ) { vaddr = ( void * ) kmem_alloc_attr ( kernel_arena , dmat -> maxsize , mflags , 0 , dmat -> lowaddr , memattr ) ; } else { vaddr = ( void * ) kmem_alloc_contig ( kernel_arena , dmat -> maxsize , mflags , 0 , dmat -> lowaddr , dmat -> alignment , dmat -> boundary , memattr ) ; } if ( vaddr == NULL ) { _busdma_free_dmamap ( newmap ) ; newmap = NULL ; } else { newmap -> sync_count = 0 ; } * vaddrp = vaddr ; * mapp = newmap ; return ( vaddr == NULL ? ENOMEM : 0 ) ; }
Allocate a piece of memory that can be efficiently mapped into
 bus device space based on the constraints lited in the dma tag.
Allocate a piece of memory that can be efficiently mapped into bus device space based on the constraints lited in the dma tag .
/*
	 * If all the memory is coherent with DMA then we don't need to
	 * do anything special for a coherent mapping request.
	 */ /* All buffers we allocate are cache-aligned. */ /*
	 * Try to find a bufzone in the allocator that holds a cache of buffers
	 * of the right size for this request.  If the buffer is too big to be
	 * held in the allocator cache, this returns NULL.
	 */ /*
	 * Allocate the buffer from the uma(9) allocator if...
	 *  - It's small enough to be in the allocator (bufzone not NULL).
	 *  - The alignment constraint isn't larger than the allocation size
	 *    (the allocator aligns buffers to their size boundaries).
	 *  - There's no need to handle lowaddr/highaddr exclusion zones.
	 * else allocate non-contiguous pages if...
	 *  - The page count that could get allocated doesn't exceed nsegments.
	 *  - The alignment constraint isn't larger than a page boundary.
	 *  - There are no boundary-crossing constraints.
	 * else allocate a block of contiguous pages because one or more of the
	 * constraints is something that only the contig allocator can fulfill.
	 */