Subject: Re: Rev 1.19 of busdma.doc
To: Jason Thorpe <thorpej@nas.nasa.gov>
From: Chris G Demetriou <Chris_G_Demetriou@ux2.sp.cs.cmu.edu>
List: tech-kern
Date: 11/09/1996 23:45:53
> int	bus_dmamap_load __P((bus_dma_tag_t tag, bus_dma_handle_t dmah,
> 	    struct uio *uio, bus_dmamap_load_func_t func, void *funcarg,
> 	    int flags));
> 
> 	bus_dmamap_load() loads a dma handle with mappings for a
> 	DMA transfer.  Arguments are as follows:
> 
> 	tag		This is the bus_dma_tag_t passed down from the
> 			parent driver via <bus>_attach_args.
> 
> 	dmah		The dma handle with which to map the
> 			transfer.
> 
> 	uio		A pointer to a struct uio, which describes
> 			the buffers involved in the DMA transfer.
> 			The uio structure will contain iovecs which
> 			describe the buffers involved in the transfer,
> 			and will set "uio_segflg" to indicate DMA
> 			to/from kernel or user address space.  If
> 			"uio_segflg" is UIO_USERSPACE, then the buffers
> 			are assumed to be in "uio_procp"'s address
> 			space.  bus_dmamap_load() will ignore the
> 			value of "uio_rw".  bus_dmamap_load() will
> 			adjust the "uio_offset" and "uio_resid"
> 			values as necessary while iterating over
> 			the uio.

Must they be wired?  (I'd say yes.)

If not? -> the user has wandered into the void.


> caddr_t	bus_dmamem_alloc __P((bus_dma_tag_t tag, size_t size,
> 	    int nsegments, bus_size_t alignment, struct proc *p,
> 	    int flags));
> 
> 	bus_dmamem_alloc() allocates memory that is "DMA safe"
> 	for the bus corresponding to the given tag and maps it
> 	into virtual address space as determined by "p" (see below).
> 	Arguments are as follows:
> 
> 	tag		The is the bus_dma_tag_t passed down from the
> 			parent driver via <bus>_attach_args.
> 
> 	size		The amount of memory to allocate.
> 
> 	nsegments	Specifies the maximum number of segments
> 			that may compose the allocated memory.  For
> 			example, if this value is 1, the entire
> 			allocated memory region must be physically
> 			contiguous.  If this value is 2, the allocated
> 			memory region may consist of up to 2
> 			physically contigious segments, etc.

No!

Not physical.  They must be mappable as one contiguous region by the
map routine.

On the Alpha, dmamem_alloc will be a wrapper around malloc() (after
checking certain size constraints, etc.) and i'm going to leave the
bus-space contiguity up to the map routine (since i have to let it do
it, anyway)...


> 	alignment	Each segment will be aligned on this boundary.
> 			Alignment must be a power of 2.  If no alignment
> 			is necessary, the value 1 should be specified.

Uh, how is this necessary or relevant?  Or, more inportantly, if it
_is_ necessary or relevant, why isn't it provided to the map routine
as well?

The mapping routine might be creating a bouncing region by which to do
its mapping (perhaps down to byte-level granularity), or it may be
doing some VDMA tricks, and will need to know this if it's a
constraint imposed by the device.


Why does dmamem_alloc() not include a max segment size, like
dmamap_create has?


I'm also concerned that there are no boundary-crossing-check bounaries
(e.g. to keep DMA from crossing a 64k boundary, which a device might
want if it's treating the memory as "device pages," perhaps doing its
own VDMA or something), device-space start-end boundaries, etc.

I actually think that those sorts of things need to be passed to both
allocate and map...  I previously thought that some of them could be
handled via the bus-defined flags, but i'm now doubting that.


The goal here is that the device should be able to specify constraints
to both dmamem_alloc() and dmamap_create() so that it can:

	(1) allocate a DMA buffer in host memory to read and write,
	    and

	(2) map that buffer, without any sort of bounce-buffering
	    (assuming, of course, that the hardware allows that at
	    all).

	(3) actually DMA to that buffer.

It should also be able to:

	(1) allocate a buffer via "some other means,"

	(2) if the bus supports bounce buffering (or buffer remapping,
	    or whatever), map that buffer,

	(3) DMA to that buffer.

If you want to be able to do both of those, and not just the latter,
then you need to provide dmamem_alloc() all of the 'interesting'
arguments that dmamap_create() would get, so that it can satisfy the
constraints so that a later load can map the memory without bouncing.

Having to pass all the arguments again is a big pain, but i don't see
any sane way to avoid it.


Oh, and while i'm at it...

Why is bus_dma_handle_t still called that, rather than bus_dmamap_t?
(The old name made sense in the context of the old function names, but
now that all of the function that operate on dmamaps are called
bus_dmamap_*...  8-)




cgd