FreeBSD/sys/mips/mips/busdma_machdep.c
/*
 * Utility function to load a linear buffer.  segp contains
 * the starting segment on entrance, and the ending segment on exit.
 * first indicates if this is the first invocation of this function.
 */
Utility function to load a linear buffer.  segp contains
the starting segment on entrance, and the ending segment on exit.
first indicates if this is the first invocation of this function.
Utility function to load a linear buffer . segp contains the starting segment on entrance and the ending segment on exit . first indicates if this is the first invocation of this function .
int
_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
    bus_size_t buflen, struct pmap *pmap, int flags, bus_dma_segment_t *segs,
    int *segp)
{
	bus_size_t sgsize;
	bus_addr_t curaddr;
	struct sync_list *sl;
	vm_offset_t vaddr = (vm_offset_t)buf;
	int error = 0;
	if (segs == NULL)
		segs = dmat->segments;
	if ((flags & BUS_DMA_LOAD_MBUF) != 0)
		map->flags |= DMAMAP_CACHE_ALIGNED;
	if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) {
		_bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags);
		if (map->pagesneeded != 0) {
			error = _bus_dmamap_reserve_pages(dmat, map, flags);
			if (error)
				return (error);
		}
	}
	CTR3(KTR_BUSDMA, "lowaddr= %d boundary= %d, "
	    "alignment= %d", dmat->lowaddr, dmat->boundary, dmat->alignment);
	while (buflen > 0) {
		KASSERT(kernel_pmap == pmap, ("pmap is not kernel pmap"));
		curaddr = pmap_kextract(vaddr);
		sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK);
		if (sgsize > dmat->maxsegsz)
			sgsize = dmat->maxsegsz;
		if (buflen < sgsize)
			sgsize = buflen;
		if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
		    map->pagesneeded != 0 && run_filter(dmat, curaddr)) {
			curaddr = add_bounce_page(dmat, map, vaddr, curaddr,
			    sgsize);
		} else {
			sl = &map->slist[map->sync_count - 1];
			if (map->sync_count == 0 ||
			    vaddr != sl->vaddr + sl->datacount) {
				if (++map->sync_count > dmat->nsegments)
					goto cleanup;
				sl++;
				sl->vaddr = vaddr;
				sl->datacount = sgsize;
				sl->busaddr = curaddr;
			} else
				sl->datacount += sgsize;
		}
		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
		    segp);
		if (sgsize == 0)
			break;
		vaddr += sgsize;
		buflen -= sgsize;
	}
cleanup:
	if (buflen != 0) {
		_bus_dmamap_unload(dmat, map);
		error = EFBIG; 
	}
	return (error);
}
int _bus_dmamap_load_buffer ( bus_dma_tag_t dmat , bus_dmamap_t map , void * buf , bus_size_t buflen , struct pmap * pmap , int flags , bus_dma_segment_t * segs , int * segp ) { bus_size_t sgsize ; bus_addr_t curaddr ; struct sync_list * sl ; vm_offset_t vaddr = ( vm_offset_t ) buf ; int error = 0 ; if ( segs == NULL ) segs = dmat -> segments ; if ( ( flags & BUS_DMA_LOAD_MBUF ) != 0 ) map -> flags |= DMAMAP_CACHE_ALIGNED ; if ( ( dmat -> flags & BUS_DMA_COULD_BOUNCE ) != 0 ) { _bus_dmamap_count_pages ( dmat , map , pmap , buf , buflen , flags ) ; if ( map -> pagesneeded != 0 ) { error = _bus_dmamap_reserve_pages ( dmat , map , flags ) ; if ( error ) return ( error ) ; } } CTR3 ( KTR_BUSDMA , " " " " , dmat -> lowaddr , dmat -> boundary , dmat -> alignment ) ; while ( buflen > 0 ) { KASSERT ( kernel_pmap == pmap , ( " " ) ) ; curaddr = pmap_kextract ( vaddr ) ; sgsize = PAGE_SIZE - ( ( u_long ) curaddr & PAGE_MASK ) ; if ( sgsize > dmat -> maxsegsz ) sgsize = dmat -> maxsegsz ; if ( buflen < sgsize ) sgsize = buflen ; if ( ( ( dmat -> flags & BUS_DMA_COULD_BOUNCE ) != 0 ) && map -> pagesneeded != 0 && run_filter ( dmat , curaddr ) ) { curaddr = add_bounce_page ( dmat , map , vaddr , curaddr , sgsize ) ; } else { sl = & map -> slist [ map -> sync_count - 1 ] ; if ( map -> sync_count == 0 || vaddr != sl -> vaddr + sl -> datacount ) { if ( ++ map -> sync_count > dmat -> nsegments ) goto cleanup ; sl ++ ; sl -> vaddr = vaddr ; sl -> datacount = sgsize ; sl -> busaddr = curaddr ; } else sl -> datacount += sgsize ; } sgsize = _bus_dmamap_addseg ( dmat , map , curaddr , sgsize , segs , segp ) ; if ( sgsize == 0 ) break ; vaddr += sgsize ; buflen -= sgsize ; } cleanup : if ( buflen != 0 ) { _bus_dmamap_unload ( dmat , map ) ; error = EFBIG ; } return ( error ) ; }
Utility function to load a linear buffer.
Utility function to load a linear buffer .
/*
		 * Get the physical address for this segment.
		 *
		 * XXX Don't support checking for coherent mappings
		 * XXX in user address space.
		 */ /*
		 * Compute the segment size, and adjust counts.
		 */ /*
	 * Did we fit?
	 */ /* XXX better return value here? */