FreeBSD/sys/x86/x86/busdma_bounce.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 .
static int
bounce_bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
    bus_dmamap_t *mapp)
{
	vm_memattr_t attr;
	int mflags;
	if (flags & BUS_DMA_NOWAIT)
		mflags = M_NOWAIT;
	else
		mflags = M_WAITOK;
	*mapp = NULL;
	if (dmat->segments == NULL) {
		dmat->segments = (bus_dma_segment_t *)malloc(
		    sizeof(bus_dma_segment_t) * dmat->common.nsegments,
		    M_DEVBUF, mflags);
		if (dmat->segments == NULL) {
			CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
			    __func__, dmat, dmat->common.flags, ENOMEM);
			return (ENOMEM);
		}
	}
	if (flags & BUS_DMA_ZERO)
		mflags |= M_ZERO;
	if (flags & BUS_DMA_NOCACHE)
		attr = VM_MEMATTR_UNCACHEABLE;
	else
		attr = VM_MEMATTR_DEFAULT;
	if ((dmat->common.maxsize <= PAGE_SIZE) &&
	   (dmat->common.alignment <= dmat->common.maxsize) &&
	    dmat->common.lowaddr >= ptoa((vm_paddr_t)Maxmem) &&
	    attr == VM_MEMATTR_DEFAULT) {
		*vaddr = malloc(dmat->common.maxsize, M_DEVBUF, mflags);
	} else if (dmat->common.nsegments >= btoc(dmat->common.maxsize) &&
	    dmat->common.alignment <= PAGE_SIZE &&
	    (dmat->common.boundary == 0 ||
	    dmat->common.boundary >= dmat->common.lowaddr)) {
		*vaddr = (void *)kmem_alloc_attr(kernel_arena,
		    dmat->common.maxsize, mflags, 0ul, dmat->common.lowaddr,
		    attr);
		dmat->bounce_flags |= BUS_DMA_KMEM_ALLOC;
	} else {
		*vaddr = (void *)kmem_alloc_contig(kernel_arena,
		    dmat->common.maxsize, mflags, 0ul, dmat->common.lowaddr,
		    dmat->common.alignment != 0 ? dmat->common.alignment : 1ul,
		    dmat->common.boundary, attr);
		dmat->bounce_flags |= BUS_DMA_KMEM_ALLOC;
	}
	if (*vaddr == NULL) {
		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
		    __func__, dmat, dmat->common.flags, ENOMEM);
		return (ENOMEM);
	} else if (vtophys(*vaddr) & (dmat->common.alignment - 1)) {
		printf("bus_dmamem_alloc failed to align memory properly.\n");
	}
	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
	    __func__, dmat, dmat->common.flags, 0);
	return (0);
}
static int bounce_bus_dmamem_alloc ( bus_dma_tag_t dmat , void * * vaddr , int flags , bus_dmamap_t * mapp ) { vm_memattr_t attr ; int mflags ; if ( flags & BUS_DMA_NOWAIT ) mflags = M_NOWAIT ; else mflags = M_WAITOK ; * mapp = NULL ; if ( dmat -> segments == NULL ) { dmat -> segments = ( bus_dma_segment_t * ) malloc ( sizeof ( bus_dma_segment_t ) * dmat -> common . nsegments , M_DEVBUF , mflags ) ; if ( dmat -> segments == NULL ) { CTR4 ( KTR_BUSDMA , " " , __func__ , dmat , dmat -> common . flags , ENOMEM ) ; return ( ENOMEM ) ; } } if ( flags & BUS_DMA_ZERO ) mflags |= M_ZERO ; if ( flags & BUS_DMA_NOCACHE ) attr = VM_MEMATTR_UNCACHEABLE ; else attr = VM_MEMATTR_DEFAULT ; if ( ( dmat -> common . maxsize <= PAGE_SIZE ) && ( dmat -> common . alignment <= dmat -> common . maxsize ) && dmat -> common . lowaddr >= ptoa ( ( vm_paddr_t ) Maxmem ) && attr == VM_MEMATTR_DEFAULT ) { * vaddr = malloc ( dmat -> common . maxsize , M_DEVBUF , mflags ) ; } else if ( dmat -> common . nsegments >= btoc ( dmat -> common . maxsize ) && dmat -> common . alignment <= PAGE_SIZE && ( dmat -> common . boundary == 0 || dmat -> common . boundary >= dmat -> common . lowaddr ) ) { * vaddr = ( void * ) kmem_alloc_attr ( kernel_arena , dmat -> common . maxsize , mflags , 0ul , dmat -> common . lowaddr , attr ) ; dmat -> bounce_flags |= BUS_DMA_KMEM_ALLOC ; } else { * vaddr = ( void * ) kmem_alloc_contig ( kernel_arena , dmat -> common . maxsize , mflags , 0ul , dmat -> common . lowaddr , dmat -> common . alignment != 0 ? dmat -> common . alignment : 1ul , dmat -> common . boundary , attr ) ; dmat -> bounce_flags |= BUS_DMA_KMEM_ALLOC ; } if ( * vaddr == NULL ) { CTR4 ( KTR_BUSDMA , " " , __func__ , dmat , dmat -> common . flags , ENOMEM ) ; return ( ENOMEM ) ; } else if ( vtophys ( * vaddr ) & ( dmat -> common . alignment - 1 ) ) { printf ( " \n " ) ; } CTR4 ( KTR_BUSDMA , " " , __func__ , dmat , dmat -> common . flags , 0 ) ; return ( 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 we succeed, no mapping/bouncing will be required */ /* 
	 * XXX:
	 * (dmat->alignment <= dmat->maxsize) is just a quick hack; the exact
	 * alignment guarantees of malloc need to be nailed down, and the
	 * code below should be rewritten to take that into account.
	 *
	 * In the meantime, we'll warn the user if malloc gets it wrong.
	 */ /* Page-based multi-segment allocations allowed */