DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
TOC PREV NEXT INDEX

Direct Memory Access (DMA)

3

3.1 Overview

Direct Memory Access (DMA) refers to data transfers initiated by a device to access system memory. This is contrasted with Programmed I/O (PIO), which involves transfers initiated by a CPU under driver software control to access registers or memory on a device.

UDI DMA services can be used to set up a UDI buffer or a piece of system memory for a DMA data transfer, to build scatter/gather lists, and to synchronize DMA caches. UDI DMA service calls use an opaque DMA handle to refer to DMA resources managed by the environment. DMA handles are allocated by udi_dma_prepare or udi_dma_mem_alloc and use the udi_dma_handle_t opaque handle type.

In order for a buffer or system memory to be usable for DMA, it must first be mapped for DMA access and a scatter/gather list describing the relevant address ranges must be built. This is accomplished using udi_dma_buf_map for UDI buffers or udi_dma_mem_alloc for shared control structures in system memory. These functions provide the driver with an IEEE 1212.1 compatible DMA scatter/gather list (see "DMA Block Vector Segment" below). The scatter/gather list contains a set of bus address-length pairs, referencing the DMA target, which the driver may use as-is, translate in place, or copy to the scatter/gather entries of its device's DMA engine, as is appropriate for its device.

If a buffer is too big to handle in one DMA transfer (for example, due to constraints on the number of scatter/gather elements that the DMA engine can support), udi_dma_buf_map will set up a partial transfer. The driver will then perform multiple transfers in order to complete the original buffer request, calling udi_dma_buf_map repeatedly to refill the scatter/gather list after each partial transfer.

3.2 DMA Block Vector Segment

As mentioned in the UDI Core Specification, Chapter 13, "Buffer Management", buffers are logically contiguous but possibly virtually and physically scattered. Such discontiguities are not visible to drivers, however, except in the way they are mapped for DMA so they can be accessed by a driver's device. The data structures in this section are used to represent the individual address-length pairs for each contiguous (from the card's viewpoint) block of data. These structures are intended to be as simple and convenient as possible for communicating between UDI and the driver. However, when mapping buffers for DMA, it would be even more advantageous if the I/O card could traverse these structures directly. To this end, UDI uses IEEE-1212.1 compatible scatter/gather structures.

I/O Block Vector Segments are IEEE-1212.1 compatible data structures that allow the I/O Unit to perform reads (writes) to (from) more than one physical segment (e.g., page) in a single request. The IEEE-1212.1 DMA Framework defines standard structures for representing physically-scattered but logically-contiguous data. There are two formats defined, one for buses with 32-bit addresses and one for 64-bit addresses, as shown in Figure 3-1.

As described in IEEE-1212.1, each address-length pair in a block vector segment points to and delimits a block of data bytes that is contiguous from the perspective of the I/O card. If the Ext bit is 0 for a pair, the address references payload data. If the Ext bit is 1, the address references an extension of the Block Vector structure itself (i.e., another array of address-length pairs) and the length indicates the physical size of this extension segment in bytes (which facilitates pre-fetch). Each block vector segment can contain at most one extension address; trees of vector segments are not allowed but chains of segments (end-to-start) are allowed. Any address-length pairs that may follow an extension address are ignored.

UDI limits its use of the flexibility allowed by IEEE-1212.1 in that for any Block Vector segment created by the environment, only the last address-length pair in a segment will ever be an indirect pointer to another Block Vector segment. All other address-length pairs will only reference data. This allows drivers for devices that are only partially IEEE-1212.1 compatible to manipulate address-length pairs without searching for indirect Block Vector references.

Environments must construct block vector segments according to the following rules (adapted from IEEE-1212.1) and the driver-specified DMA constraints (see udi_dma_constraints_attr_t).

  1. Environments should use as few segments as possible, for space and time efficiency.
  2. When extension segments are used, the UDI_SCGTH_EXT flag bit shows whether an element references payload data (0) or the next Block Vector extension segment (1). If an extension segment is referenced, the block_length field gives the size of the next segment (making it easier for the I/O Unit to handle the segment in one block-copy operation, if desired); this size includes the indirect element, if any. The length of the last segment may extend beyond the end of the last element. The driver (or device) can always realize it has reached the last element in a segment by either encountering an indirect element, or by reaching the required total data length or total number of direct elements (see scgth_num_elements in udi_scgth_t).
  3. When a data segment is referenced by block_busaddr (i.e., UDI_SCGTH_EXT is 0), the byte referenced by this I/O address will be aligned as specified by the associated DMA constraints; the block_length field, which may also be odd and will be zero, gives the number of contiguous bytes of data to be sent, or space available to receive data.
  4. The first indirect element in a vector segment causes the I/O Unit to follow to the next segment, ignoring any following address-length pairs in the current Block Vector segment. Therefore, for speed and simplicity, Block Vector Segments are single-threaded rather than stacked to build trees, arrays, or circular lists of extension segments. Only the last address-length pair in a segment will ever contain an indirect element; the last address-length pair in a Block Vector segment will only contain an indirect element, or be unused at the end of the data transfer.
  5. The total amount of data contained by the logically contiguous buffer represented by these structures is carried by some other vehicle (normally a metalanguage control block) and a transfer must be terminated when this number of bytes have been handled, regardless of whether additional bytes of buffer space are indicated by the address-length pairs. This is true for both inbound and outbound data transfers. All elements in a vector are usable.
  6. Null address values are not defined since I/O bus addresses are used and all values are valid addresses. Zero-length data segments are allowed for flexibility in use by higher software layers (however, they are not encouraged because of the slight performance impact). These shall be ignored. Block_length must not be zero if the UDI_SCGTH_EXT flag is set.
  7. All address-length pairs of a given block vector must have the same structure, 32- versus 64-bit supportive (therefore, one scgth_format value applies to the entire scatter/gather list). Also, for card/host compatibility, block vector segments will be aligned according to the address size of their format; i.e., 32-bit supportive block vector segments shall be at least 4-byte aligned, and 64-bit supportive segments shall be at least 8-byte aligned.
  8. All fields of block vector segments are endian-sensitive, including the UDI_SCGTH_EXT flag.
  9. The reserved field for the 64-bit format shall be set to zero when initialized and must be ignored when read.

3.3 DMA Service Calls and Structures

NAME udi_dma_handle_t

DMA handle type

SYNOPSIS

#include <udi.h>

typedef <HANDLE> udi_dma_handle_t;
 
/* Null handle value for udi_dma_handle_t */
 
#define  UDI_NULL_DMA_HANDLE				<NULL_HANDLE>
 

description The DMA handle type, udi_dma_handle_t, holds an opaque handle that refers to DMA resources managed by the environment.

DMA handles are not transferable between regions.

NAME udi_dma_limits

Platform-specific allocation and access limits

SYNOPSIS

#include <udi.h>

typedef struct {

	udi_size_t max_legal_contig_alloc;

	udi_size_t max_safe_contig_alloc;

	udi_size_t cache_line_size;

} udi_dma_limits_t;
 
void udi_dma_limits (

	udi_dma_limits_t *dma_limits );
 
/* Guaranteed Minimum Allocation Size */
 
#define  UDI_DMA_MIN_ALLOC_LIMIT				4000
 

MEMBERS max_legal_contig_alloc is the maximum legal size of a single DMA-able memory element (one element in a udi_scgth_t scatter/gather list) that can be requested from udi_dma_mem_alloc or udi_dma_buf_map. Any request for a larger size will produce indeterminate results, which could include termination of the driver or region, or even a complete system abort.

max_safe_contig_alloc is the maximum size of a single DMA-able memory element that should be requested from udi_dma_mem_alloc or udi_dma_buf_map without being prepared to cancel an unsuccessful allocation.

cache_line_size is the size, in bytes, of the largest cache line that affects DMA-able memory.

DESCRIPTION udi_dma_limits_t reflects the DMA memory allocation limits available on a particular system, for a particular region. These limits may vary from region to region, but will remain constant for the life of a region.

The udi_dma_limits_t structure is passed back to a driver by a call to udi_dma_limits.

Since UDI can be implemented on a wide variety of systems from small embedded systems to large server systems, the ability to provide contiguous DMA-able memory through udi_dma_mem_alloc and udi_dma_buf_map can vary widely. udi_dma_limits allows drivers to adjust their allocation algorithms to best fit their environment.

There are two types of allocation limits: legal limits and safe limits. Legal limits represent the absolute upper bound on a single allocation. Drivers must not make requests that would exceed the legal limits.

Safe limits represent the maximum amount that a driver may safely request without arranging to deal with unsuccessful allocations. For any size greater than the safe limit (but not exceeding the legal limit), drivers must cancel the request (using udi_cancel) after a reasonable amount of time has expired. To do this, they must set a timer using udi_timer_start or udi_timer_start_repeating. Drivers may also cancel allocations below the safe limit, but they are not expected to do so.

The max_legal_contig_alloc and max_safe_contig_alloc limits affect the size of a DMA-able memory element (one element in a udi_scgth_t scatter/gather list), which must be contiguous in bus address space. In most cases, DMA constraints allow the environment sufficient flexibility to use smaller pieces; in such cases, these limits wouldn't matter. However, the following DMA and transfer constraints attributes could force the environment to use larger element sizes:

UDI_DMA_ELEMENT_GRANULARITY_BITS

UDI_DMA_SCGTH_MAX_ELEMENTS

UDI_DMA_NO_PARTIAL

UDI_XFER_GRANULARITY

All of the above allocation limits are guaranteed to be greater than or equal to UDI_DMA_MIN_ALLOC_LIMIT (4000 bytes). This means drivers don't need to check these limits for requests that don't exceed 4000 bytes.

The cache_line_size value may be used to set appropriate DMA constraints for devices that need data or "slop" aligned on cache line boundaries.

REFERENCES udi_limits_t, udi_dma_mem_alloc, udi_dma_buf_map, udi_cancel

NAME udi_busaddr64_t

64-bit bus address data type

SYNOPSIS

#include <udi.h>

typedef <OPAQUE> udi_busaddr64_t;
 

DESCRIPTION The udi_busaddr64_t type used for bus addresses in the UDI_SCGTH_64 format is a self-contained opaque type that is guaranteed to be 64 bits in size and hold a bus address in the appropriate endianness. Drivers may copy udi_busaddr64_t values using assignment statements, or pass them by value or by reference to function calls, but may not use arithmetic operations or otherwise make assumptions about the internal structure of this data type. When swapping endianness of a udi_busaddr64_t value, drivers must use an 8-byte (64-bit) transaction size with a utility function to ensure proper endianness conversion (see Section 22.2.3, "Endian-Swapping Utilities," on page 22-11 of the UDI Core Specification).

warnings The udi_busaddr64_t type is not transferable between regions.

NAME udi_scgth_t

I/O Bus scatter/gather structure

SYNOPSIS

#include <udi.h>

typedef struct {

	udi_ubit32_t block_busaddr;

	udi_ubit32_t block_length;

} udi_scgth_element_32_t;
 
typedef struct {

	udi_busaddr64_t block_busaddr;

	udi_ubit32_t block_length;

	udi_ubit32_t el_reserved;

} udi_scgth_element_64_t;
 
/* Extension Flag */
 
#define  UDI_SCGTH_EXT
 
0x80000000
 
typedef struct {

	udi_ubit16_t scgth_num_elements;

	udi_ubit8_t scgth_format;

	udi_boolean_t scgth_must_swap;

	union {

	    udi_scgth_element_32_t *el32p;

	    udi_scgth_element_64_t *el64p;

	} scgth_elements;

	union {

	    udi_scgth_element_32_t el32;

	    udi_scgth_element_64_t el64;

	} scgth_first_segment;

} udi_scgth_t;
 
/* Values for scgth_format */
 
#define UDI_SCGTH_32 (1U<<0) #define UDI_SCGTH_64 (1U<<1) #define UDI_SCGTH_DMA_MAPPED (1U<<6) #define UDI_SCGTH_DRIVER_MAPPED (1U<<7)

MEMBERS block_busaddr is the I/O card-relative bus address of a contiguous block of data bytes (if UDI_SCGTH_EXT bit is cleared), or an extension array of udi_scgth_element_t elements (if UDI_SCGTH_EXT is set). These blocks are contiguous from the I/O card's perspective. See the DESCRIPTION below for comments on device endianness.

block_length is the length of the related block. If this is an extension element (the UDI_SCGTH_EXT bit is set) then this is the size in bytes of the next scatter/gather block, including the indirect element in that block, if present. If this is not an extension element then this is the size in bytes of the DMA data associated with this block_busaddr. In the UDI_SCGTH_32 format, the UDI_SCGTH_EXT bit is part of this field.

el_reserved includes the UDI_SCGTH_EXT bit in the UDI_SCGTH_64 format. Other bits are unused.

UDI_SCGTH_EXT is a mask value, to be applied to the block_length field of a udi_scgth_element_32_t or the el_reserved field of a udi_scgth_element_64_t. If this bit is set, then the scatter/gather element is an indirect reference to a possibly physically-discontiguous continuation of the scatter/gather list.

scgth_num_elements gives the number of direct udi_scgth_element_t elements included in the entire scatter/gather list (indirect elements are not included, but elements from all segments are included). This may be used to estimate I/O driver control resources.

scgth_format indicates the format of the scatter/gather elements. Exactly one of the following flags will be set in scgth_format, corresponding to the 32-bit and 64-bit scatter/gather formats, respectively:
UDI_SCGTH_32
UDI_SCGTH_64

In addition, the UDI_SCGTH_DMA_MAPPED flag will be set if the scatter/gather list is "DMA-mapped", meaning that the list elements themselves are made readable from the adapter via DMA and are in an endianness appropriate for access by the device (as indicated by the UDI_DMA_SCGTH_ENDIANNESS constraints attribute). The driver must ensure that its DMA device does not write to the scatter/gather list memory.

The UDI_SCGTH_DRIVER_MAPPED flag will be set if the scatter/gather list is (also) "driver-mapped", meaning that the list elements are readable from the driver via the el32p or el64p pointer. Otherwise, these pointers are unused and their value is unspecified. The list elements will be in the driver's endianness if and only if driver-mapped and not DMA-mapped.

The scgth_format value used for a scatter/gather list is determined by the value of the UDI_DMA_SCGTH_FORMAT constraints attribute used to create the scatter/gather list.

scgth_must_swap is a flag indicating that the driver must swap endianness when accessing driver-mapped list elements via el32p or el64p. This flag will always be FALSE if the scatter/gather list is not DMA-mapped. If not driver-mapped, the value of the flag is unspecified and must not be used. When the scatter/gather list is both DMA-mapped and driver-mapped, the driver must check this flag; it must not assume it knows whether or not to swap, based on its specified UDI_DMA_SCGTH_ENDIANNESS, since interposed bus bridges may change the endianness.

See Section 22.2, "Endianness Management," on page 22-2 of the UDI Core Specification for details on how to construct C structure definitions for proper endianness handling, and the endian swapping utilities that are available.

el32p, el64p are members of the scgth_elements union. One of these, depending on the value of scgth_format, will be set to be a pointer to the scatter/gather list in the driver's address space if UDI_SCGTH_DRIVER_MAPPED is set in scgth_format.

scgth_first_segment is only used for DMA-mapped scatter/gather lists. Depending on the value of scgth_format, el32 or el64 contains the I/O-card relative address of the beginning of the scatter/gather list and the length in bytes of the first segment in this list. scgth_first_segment is similar to an IEEE-1212.1 indirect element, except that the UDI_SCGTH_EXT bit is never set.

DESCRIPTION The udi_scgth_t structure provides a way to access the block vector array segment(s) that describe the memory addresses of a DMA-mapped data buffer or shared control structure memory. Scatter/gather lists are built by the environment as a result of calls to udi_dma_buf_map or udi_dma_mem_alloc.

Scatter/gather lists are presented in either 32-bit or 64-bit format, as requested by the driver through its DMA constraints. The format used is reported back to the driver through scgth_format. (See UDI_DMA_SCGTH_FORMAT on page page 3-18 in udi_dma_constraints_attr_t.)

Depending on the value of the UDI_DMA_SCGTH_FORMAT constraints attribute, the scatter/gather elements may be DMA-mapped, driver-mapped, or both. The driver chooses the appropriate visibility depending on how closely its device's scatter/gather format resembles the UDI scatter/gather list format (which is based on IEEE-1212.1). If they are identical, the driver should choose UDI_SCGTH_DMA_MAPPED and let its device access the scatter/gather list directly. If the formats are similar, but not identical, the driver may choose to use both UDI_SCGTH_DMA_MAPPED and UDI_SCGTH_DRIVER_MAPPED and modify the scatter/gather elements in place (being careful to observe scgth_must_swap if set) before having the device access the list. Otherwise, the driver should use just UDI_SCGTH_DRIVER_MAPPED and use separately allocated DMA-able memory or PIO to build a scatter/gather list in the appropriate format, based on the values it reads from the scgth_elements array.

If DMA-mapped, the memory for the scatter/gather segments themselves will conform to the DMA constraints related to scatter-gatter memory, and the associated udi_scgth_t structure will contain an indirect reference to the first element of the scatter/gather list in scgth_first_segment. The members of the el32 or el64 element within this union are in the driver's endianness. The block_busaddr member contains the I/O card-relative address of the beginning of the scatter/gather list, and the block_length member contains the length of the first segment of this list, including an indirect element, if any exists.

If not DMA-mapped, the scgth_first_segment field of udi_scgth_t is not valid, and the scatter/gather list will not contain extension elements (UDI_SCGTH_EXT); the entire list is provided in a single block vector segment.

The environment's use of the IEEE-1212.1 structures is such that all the udi_scgth_element_t elements in a block vector segment are used before chaining to the next segment. Therefore, the driver can use the length of the block vector segment to determine where the next indirect udi_scgth_element_t pair is, if any. Therefore, it is not necessary for the driver to check for UDI_SCGTH_EXT for other elements in the segment. Note, though, that the last segment may contain fewer elements than covered by the length of the segment; the total number of direct elements (scgth_num_elements) or the total size of the mapped memory must be used to determine that the end of the list has been reached.

warnings The udi_scgth_t type is not transferable between regions.

NAME udi_dma_constraints_t

UDI DMA constraints handle

SYNOPSIS

#include <udi.h>

typedef <HANDLE> udi_dma_constraints_t;
 
/* NULL dma constraints constant */
 
#define  UDI_NULL_DMA_CONSTRAINTS				<NULL_HANDLE>
 

DESCRIPTION When buffer data is passed to a driver, it may be required to satisfy a set of DMA constraints, such as maximum transfer size or device offset alignment. In order for drivers to express their DMA constraints UDI defines a DMA constraints object, which is accessed via an opaque dma constraints handle:

DMA Constraints handles are used by the environment to ensure that when a buffer or DMA memory is allocated by the parent, the environment can optimize the allocation appropriately to meet all the constraints along the path, potentially avoiding copies later. The environment may also add its own hidden constraints based on knowledge of how the buffer or DMA memory will be used in the rest of the operating system.

Constraints handles are transferable between regions.

Warnings Drivers must not compare handle values for equality, but the UDI_HANDLE_IS_NULL macro can be used to determine if a handle variable currently holds a null value.

references UDI_HANDLE_IS_NULL

NAME udi_dma_constraints_attr_t

DMA constraints attributes

SYNOPSIS

#include <udi.h>

typedef udi_ubit8_t udi_dma_constraints_attr_t;
 
/* DMA Convenience Attribute Codes */
 
#define  UDI_DMA_ADDRESSABLE_BITS				100
 
#define  UDI_DMA_ALIGNMENT_BITS				101
 
/* DMA Constraints on the Entire Transfer */
 
#define UDI_DMA_DATA_ADDRESSABLE_BITS 110 #define UDI_DMA_NO_PARTIAL 111
/* DMA Constraints on the Scatter/Gather List 
*/
 
#define UDI_DMA_SCGTH_MAX_ELEMENTS 120 #define UDI_DMA_SCGTH_FORMAT 121 #define UDI_DMA_SCGTH_ENDIANNESS 122 #define UDI_DMA_SCGTH_ADDRESSABLE_BITS 123 #define UDI_DMA_SCGTH_MAX_SEGMENTS 124
/* DMA Constraints on Scatter/Gather Segments 
*/
 
#define UDI_DMA_SCGTH_ALIGNMENT_BITS 130 #define UDI_DMA_SCGTH_MAX_EL_PER_SEG 131 #define UDI_DMA_SCGTH_PREFIX_BYTES 132
/* DMA Constraints on Scatter/Gather Elements 
*/
 
#define UDI_DMA_ELEMENT_ALIGNMENT_BITS 140 #define UDI_DMA_ELEMENT_LENGTH_BITS 141 #define UDI_DMA_ELEMENT_GRANULARITY_BITS 142
/* DMA Constraints for Special Addressing */
 
#define UDI_DMA_ADDR_FIXED_BITS 150 #define UDI_DMA_ADDR_FIXED_TYPE 151 #define UDI_DMA_ADDR_FIXED_VALUE_LO 152 #define UDI_DMA_ADDR_FIXED_VALUE_HI 153
/* DMA Constraints on DMA Access Behavior */
 
#define UDI_DMA_SEQUENTIAL 160 #define UDI_DMA_SLOP_IN_BITS 161 #define UDI_DMA_SLOP_OUT_BITS 162 #define UDI_DMA_SLOP_OUT_EXTRA 163 #define UDI_DMA_SLOP_BARRIER_BITS 164
/* Values for UDI_DMA_SCGTH_ENDIANNESS */
 
#define UDI_DMA_LITTLE_ENDIAN (1U<<6) #define UDI_DMA_BIG_ENDIAN (1U<<5)
/* Values for UDI_DMA_ADDR_FIXED_TYPE */
 
#define UDI_DMA_FIXED_ELEMENT 1 #define UDI_DMA_FIXED_LIST 2 #define UDI_DMA_FIXED_VALUE 3

DESCRIPTION This type is used to select a particular attribute of a constraints object. Constrants objects, referenced by constraints handles (see udi_dma_constraints_t), are used to constrain data and transfer properties to most optimally meet the requirements of all drivers handling the data.

A constraints attribute is a mnemonic constant (UDI_DMA_XXX in the tables below) which is used to set an associated value in a constraints handle. Definitions of use and the meaning of each attribute follow the tables.

There are two general types of constraints: restrictions and capabilities. Restriction constraints indicate that the operation is restricted to a specific value or set of values, and if propagated, restriction constraints typically become more constrictive with each module. For these types of constraints, there is a default value along with a minimum and maximum value (specified in the tables below or elsewhere) and the effects of the combine operation are to make the constraint the more or less restrictive value of the attributes being combined. The tables also specify any special interpretation for a constraint vaue of zero or N/A if zero is not a special case.

The capability constraints are used to indicate the various capabilities of a module and are not as simply described as the restriction constraints. Capability constraints are not usually linear values and don't have a standard meaning when used with combine operations. For these types of constraints, the most and least restrictive values are specified as "N/A" indicating that they do not apply and the description of the constraint must be consulted to determine the effects of the combine operation.

Constraints objects, referenced by constraints handles (udi_dma_constraints_t), are used to constrain transfer properties as well as memory placement of udi_buf_t data, memory allocated by udi_dma_mem_alloc, and scatter/gather lists, in order to make them addressable via DMA from a particular device.

Any driver that will be using DMA, or drives a bus bridge that has an effect on DMA transfers, must apply its DMA constraints attributes to a constraints object by calling udi_dma_constraints_attr_set. The driver must then pass the constraints handle to udi_dma_prepare or udi_dma_mem_alloc to allow the environment to allocate and/or copy the memory and mapping registers used for DMA so that they meet the specified constraints. If different DMA transactions have different alignment restrictions (e.g., transmit DMA can be byte-aligned, but receive DMA must be 4-byte aligned), the driver would need to create a separate handle for each case.

A list of supported DMA constraints attribute codes is given below, along with the range of valid values for each attribute, which of these values are considered least and most restrictive, and the default value for the attribute. This is presented in the form of a table for each attribute category; each table is followed by detailed descriptions of each attribute.

In addition to the individual attributes specified for DMA operations there are a set of convenience attributes, which are used to specify a grouping of individual attributes. For most DMA situations, there are sets of related attributes which can all be set to identical values because the DMA engine does not distinguish between the conditions represented by the individual attributes. UDI provides convenience attributes that refer to a group of individual attributes and when used, causes all the individual attributes which are part of the group to be set at once without requiring explicit specification of each individual attribute.
Table 3-1 DMA Convenience Attributes
Convenience Attribute Related Individual Attributes
UDI_DMA_ADDRESSABLE_BITS UDI_DMA_DATA_ADDRESSABLE_BITSUDI_DMA_SCGTH_ADDRESSABLE_BITS
UDI_DMA_ALIGNMENT_BITS UDI_DMA_ELEMENT_ALIGNMENT_BITSUDI_DMA_SCGTH_ALIGNMENT_BITS

UDI_DMA_ADDRESSABLE_BITS is used to simultaneously set UDI_DMA_DATA_ADDRESSABLE_BITS and UDI_DMA_SCGTH_ADDRESSABLE_BITS. This specifies the number of bits of bus address that the DMA engine can generate for access to either data or scatter/gather elements.

UDI_DMA_ALIGNMENT_BITS is used to simultaneously set UDI_DMA_ELEMENT_ALIGNMENT_BITS and UDI_DMA_SCGTH_ALIGNMENT_BITS. This specifies the # of LSB bits that must be zero in the starting bus addresses of data elements and scatter/gather segments; i.e. the starting bus addresses of data elements and scatter/gather segments must be multiples of 2^UDI_DMA_ALIGNMENT_BITS.

Table 3-2 DMA Constraints on the Entire Transfer
Valid Range Least Restrictive Value Most Restrictive Value Default Value Special Case Behavior for 0
UDI_DMA_DATA_ADDRESSABLE_BITS
16..255 255 16 255 N/A
UDI_DMA_NO_PARTIAL
0..1 0 1 0 N/A

UDI_DMA_DATA_ADDRESSABLE_BITS is the # of bits of bus address that the DMA engine can generate for access to data elements.

UDI_DMA_NO_PARTIAL is a flag indicating (if non-zero) that the device and/or driver cannot handle partial DMA mappings from udi_dma_buf_map. Either the entire request must be mapped in one call, or it must be failed.

Table 3-3 DMA Constraints on the Whole Scatter/Gather List
Valid Range Least Restrictive Value Most Restrictive Value Default Value Special Case Behavior for 0
UDI_DMA_SCGTH_MAX_ELEMENTS
0..65535 0 1 0 no restriction
UDI_DMA_SCGTH_FORMAT
see below N/A N/A see below N/A
UDI_DMA_SCGTH_ENDIANNESS
see below N/A N/A see below N/A
UDI_DMA_SCGTH_ADDRESSABLE_BITS
16..255 255 16 255 N/A
UDI_DMA_SCGTH_MAX_SEGMENTS
0..255 0 1 0 no restriction

UDI_DMA_SCGTH_MAX_ELEMENTS is the maximum # of elements that can be handled in one scatter/gather list. For DMA engines without scatter/gather support, this should be set to 1.

UDI_DMA_SCGTH_FORMAT determines the format of the scatter/gather list. It must be set to one of the legal values for the scgth_format member of udi_scgth_t, described on page 3-11. Both UDI_SCGTH_32 and UDI_SCGTH_64 may be set if the device supports both; each returned scatter/gather list's scgth_format member will indicate which mapping was used for that scatter/gather list (only one is used for the entire list and a 64-bit mapping is preferred).

The default value for this attribute is UDI_SCGTH_DMA_MAPPED + UDI_SCGTH_32.

The following attributes are relevant only to DMA-mapped scatter/gather lists and need not be set if UDI_DMA_SCGTH_FORMAT does not include UDI_SCGTH_DMA_MAPPED:

        UDI_DMA_SCGTH_ENDIANNESS
        UDI_DMA_SCGTH_ADDRESSABLE_BITS
        UDI_DMA_SCGTH_ALIGNMENT_BITS
        UDI_DMA_SCGTH_MAX_SEGMENTS
        UDI_DMA_SCGTH_MAX_EL_PER_SEG
        UDI_DMA_SCGTH_PREFIX_BYTES

UDI_DMA_SCGTH_ENDIANNESS determines the desired device endianness of DMA-mapped scatter/gather elements. This attribute may be set to one of the following values:

UDI_DMA_LITTLE_ENDIAN
UDI_DMA_BIG_ENDIAN

The default value for this attribute is unspecified. If UDI_DMA_SCGTH_FORMAT includes UDI_SCGTH_DMA_MAPPED, this attribute must be explicitly set before the constraints object can be used with udi_dma_prepare or udi_dma_mem_alloc.

Ignored if UDI_DMA_SCGTH_FORMAT does not include UDI_SCGTH_DMA_MAPPED.

UDI_DMA_SCGTH_ADDRESSABLE_BITS is the # of bits of bus address that the DMA engine can generate for accesses to scatter/gather list elements.

Ignored if UDI_DMA_SCGTH_FORMAT does not include UDI_SCGTH_DMA_MAPPED.

UDI_DMA_SCGTH_MAX_SEGMENTS is the maximum # of scatter/gather segments that the DMA engine can handle. (One segment references another through indirect scatter/gather elements.)

Ignored if UDI_DMA_SCGTH_FORMAT does not include UDI_SCGTH_DMA_MAPPED.

Table 3-4 DMA Constraints on Scatter/Gather Segments
Valid Range Least Restrictive Value Most Restrictive Value Default Value Special Case Behavior for 0
UDI_DMA_SCGTH_ALIGNMENT_BITS
0..255 0 255 0 N/A
UDI_DMA_SCGTH_MAX_EL_PER_SEG
0..65535 0 1 0 no restriction
UDI_DMA_SCGTH_PREFIX_BYTES
0..65535 0 65535 0 N/A

UDI_DMA_SCGTH_ALIGNMENT_BITS is the # of LSB bits that must be zero in the starting bus address of each scatter/gather segment); i.e. the starting bus address of each segment must be a multiple of 2^UDI_DMA_SCGTH_ALIGNMENT_BITS.

Ignored if UDI_DMA_SCGTH_FORMAT does not include UDI_SCGTH_DMA_MAPPED.

UDI_DMA_SCGTH_MAX_EL_PER_SEG is the maximum # of scatter/gather elements that can be handled in one segment, not including chain pointers to the next segment if any.

Ignored if UDI_DMA_SCGTH_FORMAT does not include UDI_SCGTH_DMA_MAPPED.

UDI_DMA_SCGTH_PREFIX_BYTES is the # bytes of extra uninitialized DMA-mapped memory that will be allocated preceding the actual scatter/gather element array in each scatter/gather segment. This is typically used to provide additional shared control structures for communicating with the device, or as space for conversion to alternate (larger) scatter/gather formats.

Alignment constraints on the starting address of scatter/gather segments will be applied to the beginning of this prefix area rather than the beginning of the element array.

From the DMA device, the prefix bytes will be accessible at bus addresses immediately preceding the bus address of the start of the segment.

Driver access to the memory, if needed, is via the same mechanism used for access to the scatter/gather elements, through the scgth_elements pointers. In this case, the scatter/gather list must also be driver-mapped.

Ignored if UDI_DMA_SCGTH_FORMAT does not include UDI_SCGTH_DMA_MAPPED.

Table 3-5 DMA Constraints on Individual Scatter/Gather Elements
Valid Range Least Restrictive Value Most Restrictive Value Default Value Special Case Behavior for 0
UDI_DMA_ELEMENT_ALIGNMENT_BITS
0..255 0 255 0 no restriction
UDI_DMA_ELEMENT_LENGTH_BITS
0..32 0 1 0 no restriction
UDI_DMA_ELEMENT_GRANULARITY_BITS
0..32 0 1 0 no restriction

UDI_DMA_ELEMENT_ALIGNMENT_BITS is the # of LSB bits that must be zero in the starting bus address of each individual scatter/gather element; i.e. the starting bus address must be a multiple of 2^UDI_DMA_ELEMENT_ALIGNMENT_BITS.

UDI_DMA_ELEMENT_LENGTH_BITS is the # bits supported for the length (in bytes) of a single scatter/gather element (block_length in udi_scgth_t). No matter what this parameter is set to, no more than UDI_DMA_ADDRESSABLE_BITS will be used.

UDI_DMA_ELEMENT_GRANULARITY_BITS is the granularity of each individual scatter/gather element. The length in bytes of each element, except the last one in the whole transfer, must be a multiple of 2^UDI_DMA_ELEMENT_GRANULARITY_BITS.

Table 3-6 DMA Constraints for Special Addressing Restrictions
Valid Range Least Restrictive Value Most Restrictive Value Default Value Special Case Behavior for 0
UDI_DMA_ADDR_FIXED_BITS
0..255 0 1 0 no fixed bits
UDI_DMA_ADDR_FIXED_TYPE
see below see below see below see below N/A
UDI_DMA_ADDR_FIXED_VALUE_LO
0..232-1 N/A N/A 0 see below
UDI_DMA_ADDR_FIXED_VALUE_HI
0..232-1 N/A N/A 0 see below

UDI_DMA_ADDR_FIXED_BITS if non-zero, indicates that some number of MSB bits are "fixed"; that is, they must have the same value for all addresses in a range. Depending on the value of UDI_DMA_ADDR_FIXED_TYPE the specified bits may be "fixed" across an entire scatter/gather list or just within each element. In most cases, it doesn't matter what the "fixed" value is, as long as it is unchanging across the required range.

The value of UDI_DMA_ADDR_FIXED_BITS indicates the number of "variable" bits less significant than the least significant "fixed" bit. (This can also be thought of as the bit number of the first fixed bit, counting from the LSB, starting with 0.) All bits more significant than the first "fixed" bit, up to the most significant bit according to UDI_DMA_ADDRESSABLE_BITS, are also "fixed".

This somewhat counter-intuitive encoding is unfortunately necessary to prevent the value from being invalidated by changes to UDI_DMA_ADDRESSABLE_BITS.

The following attributes are relevant only when UDI_DMA_ADDR_FIXED_BITS is non-zero and need not be set otherwise:

UDI_DMA_ADDR_FIXED_TYPE
UDI_DMA_ADDR_FIXED_VALUE_LO
UDI_DMA_ADDR_FIXED_VALUE_HI

UDI_DMA_ADDR_FIXED_TYPE specifies the type of "fixed" address restriction, if any. It takes one of the following values:

UDI_DMA_FIXED_ELEMENT:
Each scatter/gather element may have different "fixed" values. This would typically be for a case where the DMA engine's current address register has upper bits that don't cascade, such as ISA motherboard DMAC "page" registers.

UDI_DMA_FIXED_LIST:
The whole scatter/gather list must have the same "fixed" value. Seems an unusual case, but it's here for completeness.

UDI_DMA_FIXED_VALUE:
The "fixed" bits must be equal to the value given by the pair of UDI_DMA_ADDR_FIXED_VALUE_LO and UDI_DMA_ADDR_FIXED_VALUE_HI for the whole scatter/gather list. This would only be used by special bridge drivers for some case like multiple OS instances sharing the same bus, in which the bridge driver "knows better" than the OS since it knows it was configured to allow only a sub-portion of the bus address space to be used by this instance.

UDI_DMA_FIXED_ELEMENT is least restrictive and the default. UDI_DMA_FIXED_VALUE is the most restrictive.

Ignored if UDI_DMA_ADDR_FIXED_BITS is zero.

UDI_DMA_ADDR_FIXED_VALUE_LO is the least significant 32 bits of the required "fixed" bits value in the UDI_DMA_FIXED_VALUE case; the LSB of UDI_DMA_ADDR_FIXED_VALUE_LO corresponds to the first "fixed" bit, not to the LSB of the address as a whole.

Ignored if UDI_DMA_ADDR_FIXED_BITS is zero or UDI_DMA_ADDR_FIXED_TYPE is not UDI_DMA_FIXED_VALUE.

UDI_DMA_ADDR_FIXED_VALUE_HI is the most significant 32 bits of the required "fixed" bits value in the UDI_DMA_FIXED_VALUE case. This should rarely ever need to be set.

Ignored if UDI_DMA_ADDR_FIXED_BITS is zero or UDI_DMA_ADDR_FIXED_TYPE is not UDI_DMA_FIXED_VALUE or UDI_DMA_ADDRESSABLE_BITS minus UDI_DMA_FIXED_BITS is not greater than 32.

Table 3-7 DMA Constraints on DMA Access Behavior
Valid Range Least Restrictive Value Most Restrictive Value Default Value Special Case Behavior for 0
UDI_DMA_SEQUENTIAL
0..1 0 1 0 N/A
UDI_DMA_SLOP_IN_BITS
0..8 0 8 0 N/A
UDI_DMA_SLOP_OUT_BITS
0..8 0 8 0 N/A
UDI_DMA_SLOP_OUT_EXTRA
0..65535 0 65535 0 N/A
UDI_DMA_SLOP_BARRIER_BITS
0..255 1 0 1 no slop barrier

UDI_DMA_SEQUENTIAL is a flag indicating (if non-zero) that the DMA engine accesses memory sequentially for a data transfer, in the order listed in the scatter/gather list and in sequential address order within each element. Some environment implementations can optimize DMA transfers if they get this guarantee from the driver.

UDI_DMA_SLOP_IN_BITS is the worst-case # bits of "input slop" alignment. This indicates that DMA cycles may cause accesses to additional physical memory locations besides those explicitly listed in scatter/gather elements. Specifically, the starting (inclusive) and ending (exclusive) byte addresses of each scatter/gather element may be rounded out to boundaries that are multiples of 2^UDI_DMA_SLOP_IN_BITS for "inbound" bus transactions (i.e. from device to memory).

UDI_DMA_SLOP_OUT_BITS is the worst-case # bits of "output slop" alignment. This indicates that DMA cycles may cause accesses to additional physical memory locations besides those explicitly listed in scatter/gather elements. Specifically, the starting (inclusive) and ending (exclusive) byte addresses of each scatter/gather element may be rounded out to boundaries that are multiples of 2^UDI_DMA_SLOP_OUT_BITS for "outbound" bus transactions (i.e. from memory to device).

UDI_DMA_SLOP_OUT_EXTRA is the worst-case # bytes of "extra slop". This represents additional bytes of prefetch beyond the end of each scatter/gather element after rounding up based on UDI_DMA_SLOP_OUT_BITS. This applies during outbound bus transactions only.

UDI_DMA_SLOP_BARRIER_BITS is the # bits of "slop barrier". This represents a boundary across which UDI_DMA_SLOP_OUT_EXTRA prefetching will not occur; i.e. prefetching will not cross address boundaries that are multiples of 2^UDI_DMA_SLOP_BARRIER_BITS. This is useful to alleviate the worst-case assumptions of UDI_DMA_SLOP_OUT_EXTRA.

Ignored if UDI_DMA_SLOP_OUT_EXTRA is zero.

REFERENCES udi_dma_constraints_attr_t, udi_dma_constraints_t, udi_buf_t, udi_dma_mem_alloc, udi_dma_prepare, udi_dma_constraints_attr_set

NAME udi_dma_prepare

Prepare for DMA mapping

SYNOPSIS

#include <udi.h>

void udi_dma_prepare (

	udi_dma_prepare_call_t *callback,

	udi_cb_t *gcb,

	udi_dma_constraints_t constraints,

	udi_ubit8_t flags );
 
typedef void udi_dma_prepare_call_t (

	udi_cb_t *gcb,

	udi_dma_handle_t new_dma_handle );
 
/* Values for flags */
 
#define  UDI_DMA_OUT				(1U<<2)
 
#define  UDI_DMA_IN				(1U<<3)
 

ARGUMENTS callback, gcb are standard arguments described in the "Asynchronous Service Calls" section of "Standard Calling Sequences" in the UDI Core Specification.

constraints is a constraints handle for this device.

flags is a bitmask of flags indicating the direction(s) of transfers for which the handle will most likely be used:
UDI_DMA_OUT data transfer from memory to device
UDI_DMA_IN data transfer from device to memory

new_dma_handle is an opaque handle to the newly allocated DMA object.

DESCRIPTION udi_dma_prepare allocates a DMA handle that can be used to map UDI buffers for DMA transfer. In some cases DMA resources such as mapping registers will be pre-allocated at this time. The new DMA handle is passed to the driver with the callback.

It is intended that drivers avoid using udi_dma_prepare in the main I/O path. Where possible, it should be used at bind time, with many calls to udi_dma_buf_map being made for one call to udi_dma_prepare.

REFERENCES udi_dma_buf_map, udi_dma_free, udi_dma_constraints_t

NAME udi_dma_buf_map

Map a buffer for DMA

SYNOPSIS

#include <udi.h>

void udi_dma_buf_map (

	udi_dma_buf_map_call_t *callback,

	udi_cb_t *gcb,

	udi_dma_handle_t dma_handle,

	udi_buf_t *buf,

	udi_size_t offset,

	udi_size_t len,

	udi_ubit8_t flags );
 
typedef void udi_dma_buf_map_call_t (

	udi_cb_t *gcb,

	udi_scgth_t *scgth,

	udi_boolean_t complete,

	udi_status_t status );
 
/* Values for flags */
 
#define  UDI_DMA_OUT				(1U<<2)
 
#define  UDI_DMA_IN				(1U<<3)
 
#define  UDI_DMA_REWIND				(1U<<4)
 

ARGUMENTS callback, gcb are standard arguments described in the "Asynchronous Service Calls" section of "Standard Calling Sequences" in the UDI Core Specification.

dma_handle is the UDI DMA handle.

buf is a pointer to the UDI buffer containing the data request.

offset is the offset, in bytes, from the first valid data byte in buf at which to begin the DMA mapping. This must be less than or equal to buf->buf_size.

len is the number of bytes to map for DMA. If flags includes UDI_DMA_IN and there are fewer than len bytes of valid data in the buffer, starting at offset, then the buffer will be extended but the initial values of the new data bytes are unspecified. If flags does not include UDI_DMA_IN, offset plus len must be less than or equal to the valid data length of the buffer.

flags is a bitmask of one or more flags indicating the direction(s) and range of transfers for which the mapping applies:
UDI_DMA_OUT data transfer from memory to device
UDI_DMA_IN data transfer from device to memory
UDI_DMA_REWIND rewind to the beginning of the buffer

scgth is a pointer to a DMA scatter/gather structure.

complete is a boolean flag indicating whether the buffer was completely or partially mapped for DMA.

status is a UDI status code indicating the success or failure of the service call. If not UDI_OK, the scgth and complete values are unspecified and must be ignored.

DESCRIPTION udi_dma_buf_map allocates any additional DMA resources required to prepare the specified buffer for a DMA transfer and passes back a pointer to a DMA scatter/gather structure. The udi_scgth_t contains a set of bus address/length pairs, referencing the DMA target, which the driver may use as is, translate in place, or copy to the scatter/gather entries of its device's DMA engine, as is appropriate for its device. This scatter/gather list covers the len mapped bytes of the buffer, starting at offset.

The memory referenced by the scgth is guaranteed to meet the DMA constraints indicated by the constraints argument passed to udi_dma_prepare when dma_handle was allocated; these constraints take precedence over those associated with the buffer. Any data modified through the DMA mapping will be visible through the buffer handle once it is unmapped with udi_dma_buf_unmap.

While DMA-mapped, the buffer data must not be accessed via the buffer handle. The driver may change the buffer's buf_size value, however, but it will be ignored and ultimately overwritten by the value specified for the udi_dma_buf_unmap call.

The first time udi_dma_buf_map is called for a particular buffer using this DMA handle, the data is mapped starting at the beginning of the buffer. If the full size cannot be mapped in one piece, the complete flag is set to FALSE, indicating a partial transfer. Once this piece is complete, the driver can call udi_dma_buf_map again with the same arguments. The environment will "remember" where it left off (typically using information in the DMA handle) and will map the next section of the buffer.

To restart at the beginning of the buffer after a partial transfer, set the UDI_DMA_REWIND flag. The first call to udi_dma_buf_map for a particular buffer always starts at the beginning of the buffer, whether or not the UDI_DMA_REWIND flag is set.

At least one of UDI_DMA_IN or UDI_DMA_OUT must be specified in the flags argument, optionally combined with UDI_DMA_REWIND.

udi_dma_buf_map performs an implicit udi_dma_sync for the entire mapped range with the same UDI_DMA_IN and/or UDI_DMA_OUT flags as passed to udi_dma_buf_map.

STATUS VALUES UDI_OK is returned to indicate that the mapping completed successfully.

UDI_STAT_RESOURCE_UNAVAIL is returned to indicate a partial mapping. This value is only returned if UDI_DMA_NO_PARTIAL was not set in the constraints that were used to allocate the DMA handle and the environment is unable to map the entire request at one time. This status code indicates that the mapping has failed, the scgth pointer is NULL, and dma_handle is still unused, although new_buf may still be different than the original buf pointer.

REFERENCES udi_dma_buf_unmap, udi_dma_prepare, udi_scgth_t

NAME udi_dma_buf_unmap

Release a buffer's DMA mapping

SYNOPSIS

#include <udi.h>

udi_buf_t *udi_dma_buf_unmap (

	udi_dma_handle_t dma_handle,

	udi_size_t new_buf_size );
 

ARGUMENTS dma_handle is a DMA handle previously mapped via udi_dma_buf_map.

new_buf_size is the number of bytes of data to preserve from the mapped buffer. This becomes the new value of buf->buf_size for the buffer.

DESCRIPTION udi_dma_buf_unmap frees any resources associated with a DMA handle by a previous udi_dma_buf_map request. It should be used when a DMA transfer completes and its DMA handle is not going to be reused with the associated buffer.

If the flags passed to udi_dma_buf_map for this handle included UDI_DMA_IN, udi_dma_buf_unmap performs an implicit inbound udi_dma_sync for the entire mapped range and ensures that any data modified by the device is now visible to the driver.

If dma_handle is equal to UDI_NULL_DMA_HANDLE, explicitly or implicitly (zeroed by initial value or by using udi_memset), this function acts as a no-op. Otherwise, dma_handle must have been allocated by udi_dma_prepare.

Even if the buffer's buf_size value was changed while the buffer was mapped, the entire buffer will be unmapped. Any buffer data beyond new_buf_size at the time of the udi_dma_buf_unmap will be discarded (though the memory might not be).

WARNINGS The driver must make sure that its device is no longer accessing the buffer or control structure memory before it calls udi_dma_buf_unmap.

RETURN VALUES The udi_dma_buf_unmap function returns a buffer pointer that the driver must now use in place of the original buf. This is logically the same buffer that was passed to udi_dma_buf_map, but the environment may have reallocated it in the process of handling the DMA operation.

REFERENCES udi_dma_buf_map, udi_dma_prepare

NAME udi_dma_mem_alloc

Allocate shared control structure memory

SYNOPSIS

#include <udi.h>

void udi_dma_mem_alloc (

	udi_dma_mem_alloc_call_t *callback,

	udi_cb_t *gcb,

	udi_dma_constraints_t constraints,

	udi_ubit8_t flags,

	udi_ubit16_t nelements,

	udi_size_t element_size,

	udi_size_t max_gap );
 
typedef void udi_dma_mem_alloc_call_t (

	udi_cb_t *gcb,

	udi_dma_handle_t new_dma_handle,

	void *mem_ptr,

	udi_size_t actual_gap,

	udi_boolean_t single_element,

	udi_scgth_t *scgth,

	udi_boolean_t must_swap );
 
/* Values for flags */
 
#define  UDI_DMA_OUT				(1U<<2)
 
#define  UDI_DMA_IN				(1U<<3)
 
#define  UDI_DMA_BIG_ENDIAN				(1U<<5)
 
#define  UDI_DMA_LITTLE_ENDIAN				(1U<<6)
 
#define  UDI_DMA_NEVERSWAP				(1U<<7)
 

ARGUMENTS callback, gcb are standard arguments described in the "Asynchronous Service Calls" section of "Standard Calling Sequences" in the UDI Core Specification.

constraints is a UDI constraints handle that defines the memory constraints of the DMA engine that will be accessing the allocated memory.

flags is a bitmask of flags, that control the operation of this function.

These flags must include one or both of the following direction flags, which indicate the direction(s) of DMA transfers that may be used:

UDI_DMA_IN - transfers from device to memory.

UDI_DMA_OUT - transfers from memory to device.

The flags must also include exactly one of:

UDI_DMA_BIG_ENDIAN - access data in big endian format.

UDI_DMA_LITTLE_ENDIAN - access data in little endian format.

UDI_DMA_NEVERSWAP - access data with no byte swapping (appropriate for character data).

Finally, flags may optionally include UDI_MEM_NOZERO.

nelements indicates the number of memory elements that are to be allocated.

element_size indicates the size of each element to be allocated.

max_gap indicates the maximum number of bytes that may separate each element from the last byte of the preceeding element to the first byte of the next element. A driver will typically set this to indicate how far apart the elements may be for the device to properly address them; a max_gap of zero indicates that the elements must be adjacent in memory.

new_dma_handle is an opaque handle to the newly allocated DMA object.

mem_ptr is a driver-mapped pointer to the allocated DMA-able memory.

actual_gap indicates the actual number of bytes that separate each control structure in memory. This value will be equal to or less than the requested max_gap value unless the environment could not satisfy the requested parameters, in which case single_element will be TRUE and the actual_gap argument must be ignored. This argument must also be ignored if nelements is 1.

single_element is a flag indicating whether all elements were allocated or whether only a single element was allocated. This will return true when the allocation specified by the arguments, including the specified constraints, cannot be satisfied; in this case only one element is allocated and returned. This argument must be ignored if nelements is 1.

scgth is a pointer to a DMA scatter/gather structure for the newly allocated memory.

must_swap is a flag indicating that the driver must swap endianness when it accesses the DMA-able memory via mem_ptr. This will be computed by the environment as a function of the driver's endianness, the device endianness specified in flags, and any interceding bus bridges. Because bridges may introduce additional endianness changes, drivers must always check this flag rather than assuming swapping or not swapping.

See Section 22.2, "Endianness Management," on page 22-2 of the UDI Core Specification for details on how to construct C structure definitions for proper endianness handling, and the endian swapping utilities that are available.

DESCRIPTION Allocates control structure memory that is to be shared between a UDI device driver and its corresponding DMA device. This memory will conform to the requirements expressed in constraints. The device accesses the memory via DMA. The driver accesses the memory using the mem_ptr pointer, and must handle endian conversions if so indicated by the must_swap flag.

If the driver will be using the memory for multiple separate control structures, the nelement and element_size arguments should be used to describe the individual control structures. The system will adjust the allocation to ensure that each control structure: (1) starts on an appropriate alignment boundary, (2) does not share cache lines with other control structures, and (3) is physically contiguous. This adjustment is indicated by the actual_gap value returned on the callback which indicates the number of additional bytes allocated between each control structure to satisfy the individual alignment requirements. This gap will not exceed the device's capabilities as indicated by the max_gap argument; if the required gap size would exceed this value, then only a single element is allocated as indicated by the single_element argument.

Each gap represents actual allocated memory bytes; these bytes appear in both the virtual and the DMA-mapped address ranges and the driver should make appropriate considerations for accessing each element. There is no gap following the last element allocated.

The newly allocated memory will be zeroed unless UDI_MEM_NOZERO is set, in which case the initial values are unspecified.

The newly allocated memory will be aligned on the most restrictive alignment of the platform's natural alignments for long and pointer data types, allowing the allocated memory to be directly accessed as C structures.

At the time of the callback, the memory is mapped for DMA access by the device. The DMA mapped memory remains allocated and mapped until new_dma_handle is freed by a call to udi_dma_free or udi_dma_mem_to_buf, at which point the memory will be automatically unmapped and deallocated. udi_dma_mem_to_buf allows a range of data from the control structure memory to be placed into a UDI buffer.

Note - Unlike udi_dma_buf_map, udi_dma_mem_alloc will always produce a complete mapping.

This call is typically used for allocating memory that is contiguous from the device's perspective, but some devices may support discontiguous control memory. Whether or not contiguous device addresses are used is under control of the UDI_DMA_SCGTH_MAX_ELEMENTS property of the constraints handle, but the memory will always be virtually contiguous when accessed through the mem_ptr pointer. See udi_dma_constraints_attr_t (DMA) for details on DMA constraints.

Note - In order to use the byte-by-byte structure layout technique for mixed endianness access to shared control structure memory, and the utility macros defined in Section 22.2, "Endianness Management," on page 22-2 of the UDI Core Specification, the driver must declare two versions of the relevant structure(s), type-casting appropriately, and using the version that matches the device's endianness if must_swap is FALSE, or the "anti-endian" version if must_swap is TRUE.

REFERENCES udi_dma_limits, udi_dma_constraints_attr_t, udi_dma_prepare, udi_dma_buf_map, udi_dma_free, udi_dma_sync, udi_dma_mem_barrier, udi_scgth_t, udi_dma_mem_to_buf

NAME udi_dma_sync

Sync host & device views of DMA-able memory

SYNOPSIS

#include <udi.h>

void udi_dma_sync (

	udi_dma_sync_call_t *callback,

	udi_cb_t *gcb,

	udi_dma_handle_t dma_handle, 

	udi_size_t offset,

	udi_size_t length,

	udi_ubit8_t flags );
 
typedef void udi_dma_sync_call_t (

	udi_cb_t *gcb );
 
/* Values for flags */
 
#define  UDI_DMA_OUT				(1U<<2)
 
#define  UDI_DMA_IN				(1U<<3)
 

ARGUMENTS callback, gcb are standard arguments described in the "Asynchronous Service Calls" section of "Standard Calling Sequences" in the UDI Core Specification.

dma_handle is a DMA handle previously mapped via udi_dma_buf_map or udi_dma_mem_alloc.

offset is a logical offset into the mapped buffer data. That is, it is relative to the offset value provided to udi_dma_buf_map.

length is the length, in bytes, of the area to synchronize. When length is zero, it applies to the entire data object referenced by dma_handle, and offset must be zero.

flags indicates which view of the buffer to synchronize. The flags argument may be set to one or more of the following values:

UDI_DMA_OUT - sync before starting an outbound DMA to the device

UDI_DMA_IN - sync after completing an inbound DMA from the device

DESCRIPTION udi_dma_sync is used to synchronize the host and device views of a data object that has been loaded for DMA. This may involve flushes of CPU or I/O caches, or assuring that hardware write buffers have drained.

The required direction flags depend on the direction(s) of I/O transactions since the last synchronization points. If the buffer has been modified by the CPU, and is going to be read by the device's DMA engine, then udi_dma_sync must be called with UDI_DMA_OUT set. This ensures that the device's DMA engine sees the changes previously made to the buffer memory by the driver. If the device's DMA engine has written to the buffer, and it is going to be read by the driver, udi_dma_sync must be called with UDI_DMA_IN set. This makes sure the CPU's view of the memory includes any changes previously made by the device's DMA engine.

Note that the UDI_DMA_OUT and/or UDI_DMA_IN flags must have been set in the call to udi_dma_prepare or udi_dma_mem_alloc if the same flag is to be set in udi_dma_sync.

REFERENCES udi_dma_buf_map, udi_dma_buf_unmap, udi_dma_mem_alloc, udi_dma_mem_barrier, udi_dma_scgth_sync

NAME udi_dma_scgth_sync

Sync host & device views of scatter/gather list

SYNOPSIS

#include <udi.h>

void udi_dma_scgth_sync (

	udi_dma_scgth_sync_call_t *callback,

	udi_cb_t *gcb,

	udi_dma_handle_t dma_handle );
 
typedef void udi_dma_scgth_sync_call_t (

	udi_cb_t *gcb );
 

ARGUMENTS callback, gcb are standard arguments described in the "Asynchronous Service Calls" section of "Standard Calling Sequences" in the UDI Core Specification.

dma_handle is a DMA handle previously mapped via udi_dma_buf_map or udi_dma_mem_alloc.

DESCRIPTION udi_dma_scgth_sync is used to synchronize the host and device views of the scatter/gather list memory for a data object that has been loaded for DMA, since udi_dma_sync only affects the actual data memory. This may involve flushes of CPU or I/O caches, or assuring that hardware write buffers have drained.

The entire set of scatter/gather elements, in all segments, as well as any prefix bytes (UDI_DMA_SCGTH_PREFIX_BYTES in udi_dma_constraints_attr_t) included in the synchronization. It is assumed that the DMA device did not write to this memory unless UDI_DMA_SCGTH_PREFIX_BYTES was greater than zero, but the driver may have read and/or written.

This function is only needed when the scatter/gather list is both DMA-mapped and driver-mapped (see udi_scgth_t), since this is the only case in which the driver will write to the scatter/gather segment memory and the device will read from it, and must not be used in other cases. In this case, udi_dma_scgth_sync must be called before the device reads from the scatter/gather list.

REFERENCES udi_dma_buf_map, udi_dma_mem_alloc, udi_dma_sync

NAME udi_dma_mem_barrier

Ordering barrier for accesses to DMA-able memory

SYNOPSIS

#include <udi.h>

void udi_dma_mem_barrier (

	udi_dma_handle_t dma_handle );
 

ARGUMENTS dma_handle is a DMA handle previously allocated by udi_dma_mem_alloc.

DESCRIPTION udi_dma_mem_barrier is used to impose ordering constraints between driver accesses to shared control structure memory allocated by udi_dma_mem_alloc.

This ensures that no loads or stores to the memory associated with dma_handle that are executed after the call to udi_dma_mem_barrier will be visible to the device until all prior loads or stores are visible.

REFERENCES udi_dma_mem_alloc, udi_dma_sync

NAME udi_dma_free

Free DMA resources

SYNOPSIS

#include <udi.h>

void udi_dma_free (

	udi_dma_handle_t dma_handle );
 

ARGUMENTS dma_handle is a DMA handle allocated by udi_dma_prepare or udi_dma_mem_alloc.

DESCRIPTION udi_dma_free frees a DMA handle and any associated resources allocated by udi_dma_prepare or udi_dma_mem_alloc.

If the dma_handle is associated with shared control structure memory allocated by udi_dma_mem_alloc, the allocated memory will be freed, as will the scatter/gather list.

If the dma_handle was mapped to a buffer with udi_dma_buf_map, it must be unmapped (using udi_dma_buf_unmap) before udi_dma_free is called.

If dma_handle is equal to UDI_NULL_DMA_HANDLE, explicitly or implicitly (zeroed by initial value or by using udi_memset), this function acts as a no-op. Otherwise, dma_handle must have been allocated by udi_dma_prepare or udi_dma_mem_alloc.

Note - udi_dma_free does not do a udi_dma_sync operation.

warnings The driver must make sure that its device is no longer accessing the buffer or control structure memory before it calls udi_dma_free.

REFERENCES udi_dma_prepare, udi_dma_buf_map, udi_dma_buf_unmap, udi_dma_mem_alloc

NAME udi_dma_mem_to_buf

Convert DMA-mapped control memory into a buffer

SYNOPSIS

#include <udi.h>

void udi_dma_mem_to_buf (

	udi_dma_mem_to_buf_call_t *callback,

	udi_cb_t *gcb,

	udi_dma_handle_t dma_handle,

	udi_size_t src_off,

	udi_size_t src_len,

	udi_buf_t *dst_buf );
 
typedef void udi_dma_mem_to_buf_call_t (

	udi_cb_t *gcb,

	udi_buf_t *new_dst_buf );
 

ARGUMENTS callback, gcb are standard arguments described in the "Asynchronous Service Calls" section of "Standard Calling Sequences" in the UDI Core Specification.

dma_handle is a DMA handle previously allocated by udi_dma_mem_alloc.

src_off is the beginning offset from the first byte of the shared control structure memory to include in the destination buffer.

src_len is the number of bytes to include from the destination buffer.

dst_buf is the same argument as used in udi_buf_copy.

new_dst_buf is a pointer to a UDI buffer containing the indicated data.

DESCRIPTION udi_dma_mem_to_buf frees a DMA handle and any associated resources allocated by udi_dma_mem_alloc, except the data from the indicated range of the memory block are used as the initial contents of a newly-allocated buffer.

The constraints that were used to allocate dma_handle shall also be used to allocate new_dst_buf.

udi_dma_mem_to_buf is typically used for inbound data from devices that store both shared control structures and data in the same piece of memory.

references udi_dma_mem_alloc, udi_buf_write

3.4 DMA Constraints Handle Transferability

Since DMA Constraints handles are transferable between regions, they need to be represented in layout specifiers for use by metalanguages and by drivers that specify inline layouts. This section defines an extension to the data layout specifier defined in the UDI Core Specification.

NAME udi_layout_t (DMA)

Data layout specifier for DMA

SYNOPSIS

#include <udi.h>

typedef udi_ubit8_t udi_layout_t;
 
/* DMA Constraints Handle Layout Element Type Code */
 
#define  UDI_DL_DMA_CONSTRAINTS_T				201
 

Description This page lists additional layout specifier codes that can be used with the udi_layout_t type, defined in the UDI Core Specification, to specify DMA-related data layouts.

A data layout specifier consists of an array of one or more udi_layout_t layout elements. Each element contains a type code indicating one of the UDI data types that can be passed into a channel operation, either as a field in the control block or as an additional parameter. Each successive element of the array represents successive offsets within the described structure, with padding automatically inserted for alignment purposes as if the specified data types had appeared in a C struct declaration.

A UDI_DL_DMA_CONSTRAINTS_T layout element represents a DMA Constraints handle, of type udi_dma_constraints_t, which may be UDI_NULL_DMA_CONSTRAINTS.

References udi_layout_t, udi_dma_constraints_t


TOC PREV NEXT INDEX