--- busdma.txt Fri May 23 13:27:58 2003 +++ busdma-gibbs.txt Fri May 23 13:26:37 2003 @@ -76,10 +76,13 @@ STRUCTURES AND TYPES bus_dma_tag_t A machine-dependent (MD) opaque type that describes the charac- - teristics of DMA memory. DMA tags are organized in a hierarchi- - cal way. A parent tag should set the initial constraints of a - DMA transfer. A child tag inherits properties from its parent - tag, and can only add restrictions. + teristics of DMA memory. DMA tags are organized into a + hierarchy, with each child tag inheriting the restrictions + of its parent. This allowing all devices along the path of + a DMA operation to contribute to the restrictions placed on + each transaction. This ensures that all transactions adhere + to the lowest common denomenator of restrictions along the + path the DMA will take. bus_dma_segment_t A machine-dependent type that describes individual DMA segments. @@ -87,10 +90,13 @@ bus_addr_t ds_addr; bus_size_t ds_len; - The ds_addr field contains the address of the DMA segment, and - ds_len contains the length of the DMA segment. The fields are - suitable for programming into DMA controller address and length - registers. + The ds_addr field contains the device visible address of the + DMA segment, and ds_len contains the length of the DMA segment. + Although the DMA segments returned by a mapping call will + adhere to all restrictions necessary for a successful DMA + operation, some conversion (for instance a conversion from + host byte order to the device's byte order) is almost always + required when presenting segment information to the device. bus_dmamap_t A machine-dependent opaque type describing an individual map- @@ -103,57 +109,56 @@ Allocates a device specific DMA tag, and initializes it accord- ing to the arguments provided: parent Indicates restrictions between the parent bridge, - CPU memory, and the device. If NULL, then it is - assumed that parent tag is to be created. - alignment Required alignment of the memory region that will - be allocated for this tag. This argument only has - affect on later calls to bus_dmamem_alloc() but - not on bus_dmamap_create(). Use 1 for no specific - alignment requirements. - boundary Boundary constraints (if any) on the target DMA - memory region. For example, value of 64 indicates - that the regions created with this tag should not - cross 64 kB boundaries. `0' should be used when - there is a `no boundary' condition. The value - supplied to this argument has to be a power of 2, - and the boundary must be no larger than - BUS_SPACE_MAXSIZE. - lowaddr Low address of the target memory region restricted - to the DMA engine of a device from mapping, for - example, if the device is on the ISA bus, then - this would be BUS_SPACE_MAXADDR_24BIT, and - BUS_SPACE_MAXADDR_32BIT if on PCI or similar bus. - This value can be different depending on the plat- - form. When creating child (descendent) tags, - lowaddr should be BUS_SPACE_MAXADDR. - highaddr High address of the target memory region - restricted to the DMA engine of a device from map- - ping. This should be set to BUS_SPACE_MAXADDR, - but depending on the platform, the high address - can be larger than a 32 bit quantity. - filtfunc Filter function to provide a finer level of con- - trol if a device's DMA mapping constraints cannot - be encompassed within a single memory region. - filtfuncarg Argument for the filter function. This is nor- - mally a soft context (softc) of a driver etc. - maxsegsz Maximum size of a segment in any DMA mapped region - associated with dmat. - maxsize Maximum size (in bytes) of DMA transfers that may - be allocated through this tag. This is usually - MAXBSIZE. + CPU memory, and the device. May be NULL, if no + DMA restrictions are to be inherited. + alignment Required alignment, in bytes, of any region later + mapped using this tag. The alignment must be a + power of 2. Hardware that can DMA starting at any + address would specify "1" (2 to the zero power) for + single byte alignment. Hardware requiring DMA + transfers to start on an even multiple of 4K would + specify 4096. + boundary Boundary constraints on the target DMA memory + region. The boundary indicates the set of + addresses (all multiples of the boundary argument) + that cannot be crossed by a single bus_dmasegment_t. + For example, a value of 64 guarantees that no + single segment will contain addresses below and + above 64 and multples of 64. `0' indicates that + there are no boundary restrictions (multiples of + 0 are 0 and negative addresses don't occur in + DMA). The boundary must be either a power of 2 + or 0. + highaddr + lowaddr + Bounds of the window of bus address space + that *cannot* be directly accessed by the device. + For example, a device incapable of dmaing above + 4GB, would specify a highaddr of BUS_SPACE_MAXADDR + and a lowaddr of BUS_SPACE_MAXADDR_32BIT. + Similarly a device that can only dma to addresses + above 4GB would specify a highaddr of + BUS_SPACE_MAXADDR_32BIT and a lowaddr of 0. +/*XXX Should probably be a fully specified function prototype */ + filtfunc Optional filter function (may be NULL) to be + called for any attempt to map memory into the + window described by higaddr and lowaddr. The + filtfunc should return zero for any mapping that + can be accomodated by the device and non-zero + otherwise. This allows for a finer level of + control if a device's DMA mapping constraints + cannot be described by a single memory window. + filtfuncarg Argument passed to all calls to the filter function + for this tag. + maxsegsz Maximum size (in bytes) of a segment in any DMA + mapped region associated with dmat. + maxsize Maximum size (in bytes) of the sum of all segment + lengths in a given DMA mapping associated with + this tag. nsegments Number of discontinuities (scatter/gather seg- ments) allowed in a DMA mapped region. If there - is no restriction, then this should be set to - BUS_SPACE_UNRESTRICTED, although it is recommended - that this be used when creating parent tags and - impose the actual restrictions on the child tags. - Nsegments which have values high as - BUS_SPACE_UNRESTRICTED should not be used to cre- - ate DMA mappings, and only for creating parent - tags. - - NOTE: Very high values (200-250) supplied to this - argument can cause the kernel stack to overflow. + is no restriction, BUS_SPACE_UNRESTRICTED may + be specified. flags Are as follows: BUS_DMA_ALLOCNOW Allocate the necessary resources, like bounce pages at @@ -163,12 +168,15 @@ dmat Pointer to a bus_dma_tag_t where the resulting DMA tag will be stored. +/* XXX Shouldn't this be in the ERRORS section? */ Returns ENOMEM if sufficient memory is not avail- able for tag creation or allocating bounce pages. bus_dma_tag_destroy(dmat) Deallocate a DMA tag created by bus_dma_tag_create(). +/* XXX Need arguments */ + Returns EBUSY if any DMA maps remain associated with dmat or 0 on success. @@ -177,11 +185,14 @@ dmat DMA tag. flags The value of this argument is currently undefined and should be specified as 0. +/* XXX What about BUS_DMA_ALLOCNOW */ mapp This is a pointer to a bus_dmamap_t. A DMA map will be allocated and pointed to by mapp upon successful completion of this routine. - Returns ENOMEM if sufficient memory is not available + + + for creating the map or allocating bounce pages. bus_dmamap_destroy(dmat, map) @@ -193,47 +204,63 @@ Returns EBUSY if bounce pages are still associated with map. bus_dmamap_load(dmat, map, buf, buflen, *callback, ...) - Loads a DMA map (created by bus_dmamap_create()) for a DMA - transfer. A segment descriptor array, composed of bus_dma_seg- - ment_t type elements is passed to the callback routine, which - processes the successfully loaded DMA map, or an error from the - delayed load map. Bounce buffers are allocated, and pages of - the passed buffer, buf are checked for validity and conformance - with respect to the tag. Arguments are as follows: + Creates a mapping in device visable address space of "buflen" + bytes of "buf", associated with the DMA map "map". + Arguments are as follows: + dmat DMA tag. map The DMA map. buf The buffer to be used for the DMA transfer. buflen The size of the buffer. callback callback_arg - The callback function, and its argument. - flags The value of this argument is currently undefined, and - should be specified as 0. + The callback routine has the following format: - The callback routine and its arguments explained: - bus_dmamap_callback_t(void *arg, bus_dma_segment_t *seg, - int nseg, int error) - arg Same as callback_arg passed to + void callback(void *arg, bus_dma_segment_t *seg, + int nseg, int error); + arg Same as callback_arg passed to bus_dmamap_load(). - seg Array of DMA segment descriptors. - nseg Number of segments in seg. - error If error is set to EFBIG, only the permitted - number of segment descriptors will be stored - in the array, thus indicating a segment - limit overflow. Handling of this error sit- - uation is the responsibility of the client. - - As noted above, if a DMA tag is created with BUS_DMA_ALLOCNOW, - bus_dmamap_load() will never block. If the required amount of - bounce buffers are not available, then the request will be - queued, and the callback will be called when they are available - and EINPROGRESS is returned. - - If a call to bus_dmamap_load() fails, the mapping in the DMA map - will be invalid. It is the responsibility of the caller to - clean up any inconsistent device state. - - Returns ENOMEM if sufficient bounce pages cannot be reserved for - completing the operation. + seg Array of DMA segment descriptors. + nseg Number of segments in seg. + error Indication of the disposition of the mapping + + flags The value of this argument is currently undefined, and + should be specified as 0. +/* + XXX What about BUS_DMA_NOWAIT? You shouldn't have to specify allocnow + in all tags to get this behavior if every once in a while you want + to see if an additional mapping is cheap to perform. + */ + + Return values to the caller are as follows: + + 0 The mapping was successfull and the callback has + been called and completed. + + EINPROGRESS The mapping has been deferred for lack of + resources. The callback will be called + as soon as resources are available. Callbacks + are serviced in FIFO order. + + EINVAL The load request was invalid. The callback + has not, and will not be called. This errno + may indicate that dmat, map, buf, or callback + were invalid, or busflen was larger than + the maxsize argument used to create the dma tag. + + When the callback is called, it is presented with an error + value indicating the disposition of the mapping. Error may + be one of the following: + + 0 The mapping was successfull and the "dm_segs" + callback argument contains an array of + bus_dma_segment_t elements describing the + mapping. This array is only valid during + the scope of the callback function. + + EFBIG A mapping could not be achieved within + the segment constraints provided in the + tag even though the requested allocation + size was less than maxsize. bus_dmamap_load_mbuf(dmat, map, mbuf, ...) This is a variation of bus_dmamap_load() which maps mbuf chains @@ -285,8 +312,7 @@ This function ensures that the host and the client have a con- sistent view of the DMA memory, before and after a DMA opera- tion. This function must be called to synchronize DMA buffers - before and after a DMA operation. Other bus_dma functions can - not be relied upon, to do this synchronization implicitly. + before and after a DMA operation. If DMA read and write operations are not preceded and followed by the appropriate synchronization operations, behavior is unde- @@ -312,14 +338,6 @@ Returns ENOMEM if sufficient memory is not available for completing the operation. - bus_dmamem_alloc_size(dmat, **vaddr, flags, mapp, size) - A variant of the bus_dmamem_alloc() routine that accepts a size - argument. The purpose of the size argument is to allow the - caller to specify a specific size for the allocation, instead of - using the maximum available. If size is bigger than the maxi- - mum, that can be encompassed by the DMA tag, then ENOMEM is - returned. - bus_dmamem_free(dmat, *vaddr, map) Frees memory previously allocated by bus_dmamem_alloc(). Any mappings will be invalidated. Arguments are as follows: @@ -327,16 +345,11 @@ vaddr Kernel virtual address of the memory. map DMA map to be invalidated. - bus_dmamem_free_size(dmat, *vaddr, map, size) - A variant of the bus_dmamem_free() routine that accepts a size - argument. It should be used when freeing memory allocated with - bus_dmamem_alloc_size(). - RETURN VALUES Behavior is undefined if invalid arguments are passed to any of the above functions. If sufficient resources cannot be allocated for a given - transaction, ENOMEM is returned. All routines that are not of type, - void, will return 0 on success or an error code, as discussed above. + transaction, ENOMEM is returned. All non-void routines will return 0 on + success or an error code, which are discussed above respectively. All void routines will succeed if provided with valid arguments. @@ -350,12 +363,10 @@ HISTORY The bus_dma interface first appeared in NetBSD 1.3. - The bus_dma API was adopted from NetBSD when the FreeBSD/Alpha port was - under development. The alterations to the original API were aimed to - give the underlying implementation more flexibility on how to represent - DMA maps and DMA tags, i.e. if the underlying implementation (MD layer) - encounters a no-op abstraction, it can implement it without allocation of - per transaction resources. + The bus_dma API was adopted from NetBSD for use in the CAM SCSI subsystem. + The alterations to the original API were aimed to remove the need for + a bus_dma_sement_t array stored in each bus_dma_map while allowing + callers to queue up on scarce resources. AUTHORS The bus_dma interface was designed and implemented by Jason R. Thorpe of @@ -372,8 +383,7 @@ alterations made by Hiten Pandya. BUGS - DMA-safe regions are not allocated in segments. - - Some architectures are still using BUS_DMA_ISA. + - DMA-safe regions are not allocated in segments. + - Some architectures are still using BUS_DMA_ISA. FreeBSD 4.8 February 8, 2003 FreeBSD 4.8