BUS_DMA(9) | NetBSD Kernel Developer's Manual | BUS_DMA(9) |
int
bus_dmamap_create(bus_dma_tag_t tag, bus_size_t size, int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp);
void
bus_dmamap_destroy(bus_dma_tag_t tag, bus_dmamap_t dmam);
int
bus_dmamap_load(bus_dma_tag_t tag, bus_dmamap_t dmam, void *buf, bus_size_t buflen, struct lwp *l, int flags);
int
bus_dmamap_load_mbuf(bus_dma_tag_t tag, bus_dmamap_t dmam, struct mbuf *chain, int flags);
int
bus_dmamap_load_uio(bus_dma_tag_t tag, bus_dmamap_t dmam, struct uio *uio, int flags);
int
bus_dmamap_load_raw(bus_dma_tag_t tag, bus_dmamap_t dmam, bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags);
void
bus_dmamap_unload(bus_dma_tag_t tag, bus_dmamap_t dmam);
void
bus_dmamap_sync(bus_dma_tag_t tag, bus_dmamap_t dmam, bus_addr_t offset, bus_size_t len, int ops);
int
bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size, bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags);
void
bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs);
int
bus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs, size_t size, void **kvap, int flags);
void
bus_dmamem_unmap(bus_dma_tag_t tag, void *kva, size_t size);
paddr_t
bus_dmamem_mmap(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs, off_t off, int prot, int flags);
int
bus_dmatag_subregion(bus_dma_tag_t tag, bus_addr_t min_addr, bus_addr_t max_addr, bus_dma_tag_t *newtag, int flags);
void
bus_dmatag_destroy(bus_dma_tag_t tag);
Unless otherwise noted, all function calls in this interface may be defined as cpp(1) macros.
bus_addr_t ds_addr; bus_size_t ds_len;
The structure may have machine-dependent members and arbitrary layout. The values in ds_addr and ds_len are suitable for programming into DMA controller address and length registers.
bus_size_t dm_maxsegsz; bus_size_t dm_mapsize; int dm_nsegs; bus_dma_segment_t *dm_segs;
The structure may have machine-dependent members and arbitrary layout. The dm_maxsegsz member indicates the maximum number of bytes that may be transferred by any given DMA segment. The dm_mapsize member indicates the size of the mapping. A value of 0 indicates the mapping is invalid. The dm_segs member may be an array of segments or a pointer to an array of segments. The dm_nsegs member indicates the number of segments in dm_segs.
Behavior is not defined if invalid arguments are passed to bus_dmamap_create().
Returns 0 on success, or an error code to indicate mode of failure.
In the event that the DMA handle contains a valid mapping, the mapping will be unloaded via the same mechanism used by bus_dmamap_unload().
Behavior is not defined if invalid arguments are passed to bus_dmamap_destroy().
If given valid arguments, bus_dmamap_destroy() always succeeds.
As noted above, if a DMA handle is created with BUS_DMA_ALLOCNOW, bus_dmamap_load() will never block.
If a call to bus_dmamap_load() fails, the mapping in the DMA handle will be invalid. It is the responsibility of the caller to clean up any inconsistent device state resulting from incomplete iteration through the uio.
Behavior is not defined if invalid arguments are passed to bus_dmamap_load().
Returns 0 on success, or an error code to indicate mode of failure. Possible error codes include the following:
If the DMA handle was created with BUS_DMA_ALLOCNOW, bus_dmamap_unload() will not free the corresponding resources which were allocated by bus_dmamap_create(). This is to ensure that bus_dmamap_load() will never block on resources if the handle was created with BUS_DMA_ALLOCNOW.
bus_dmamap_unload() will not perform any implicit synchronization of DMA buffers. This must be done explicitly by bus_dmamap_sync().
bus_dmamap_unload() will restore the dm_maxsegsz member to its initial value assigned by bus_dmamap_create().
Behavior is not defined if invalid arguments are passed to bus_dmamap_unload().
If given valid arguments, bus_dmamap_unload() always succeeds.
More than one operation may performed in a given synchronization call. Mixing of PRE and POST operations is not allowed, and behavior is undefined if this is attempted.
Synchronization operations are expressed from the perspective of the host RAM, e.g., a device -> memory operation is a READ and a memory -> device operation is a WRITE.
bus_dmamap_sync() may consult state kept within the DMA map to determine if the memory is mapped in a DMA coherent fashion. If so, bus_dmamap_sync() may elect to skip certain expensive operations, such as flushing of the data cache. See bus_dmamem_map() for more information on this subject.
On platforms which implement a weak memory access ordering model, bus_dmamap_sync() will always cause the appropriate memory barriers to be issued.
This function exists to ensure that the host and the device have a consistent view of a range of DMA memory, before and after a DMA operation.
An example of using bus_dmamap_sync(), involving multiple read-write use of a single mapping might look like this:
bus_dmamap_load(...); while (not done) { /* invalidate soon-to-be-stale cache blocks */ bus_dmamap_sync(..., BUS_DMASYNC_PREREAD); [ do read DMA ] /* copy from bounce */ bus_dmamap_sync(..., BUS_DMASYNC_POSTREAD); /* read data now in driver-provided buffer */ [ computation ] /* data to be written now in driver-provided buffer */ /* flush write buffers and writeback, copy to bounce */ bus_dmamap_sync(..., BUS_DMASYNC_PREWRITE); [ do write DMA ] /* probably a no-op, but provided for consistency */ bus_dmamap_sync(..., BUS_DMASYNC_POSTWRITE); } bus_dmamap_unload(...);
This function must be called to synchronize DMA buffers before and after a DMA operation. Other bus_dma functions can not be relied on to do this synchronization implicitly. If DMA read and write operations are not preceded and followed by the appropriate synchronization operations, behavior is undefined.
Behavior is not defined if invalid arguments are passed to bus_dmamap_sync().
If given valid arguments, bus_dmamap_sync() always succeeds.
The mapping of this memory is machine-dependent (or "opaque"); machine-independent code is not to assume that the addresses returned are valid in kernel virtual address space, or that the addresses returned are system physical addresses. The address value returned as part of segs can thus not be used to program DMA controller address registers. Only the values in the dm_segs array of a successfully loaded DMA map (using bus_dmamap_load()) can be used for this purpose.
Allocations will always be rounded to the hardware page size. Callers may wish to take advantage of this, and cluster allocation of small data structures. Arguments are as follows:
All pages allocated by bus_dmamem_alloc() will be wired down until they are freed by bus_dmamem_free().
Behavior is undefined if invalid arguments are passed to bus_dmamem_alloc().
Returns 0 on success, or an error code indicating mode of failure.
Behavior is undefined if invalid arguments are passed to bus_dmamem_free().
If given valid arguments, bus_dmamem_free() always succeeds.
Later, when this memory is loaded into a DMA map, machine-dependent code will take whatever steps are necessary to determine if the memory was mapped in a DMA coherent fashion. This may include checking if the kernel virtual address lies within uncached address space or if the cache-inhibit bits are set in page table entries. If it is determined that the mapping is DMA coherent, state may be placed into the DMA map for use by later calls to bus_dmamap_sync().
Note that a device driver must not rely on BUS_DMA_COHERENT for correct operation. All calls to bus_dmamap_sync() must still be made. This flag is provided only as an optimization hint to machine-dependent code.
Also note that this flag only applies to coherency between the CPU and memory. Coherency between memory and the device is controlled with a different flag. See the description of the bus_dmamap_load() function.
Behavior is undefined if invalid arguments are passed to bus_dmamem_map().
Returns 0 on success, or an error code indicating mode of failure.
Behavior is undefined if invalid arguments are passed to bus_dmamem_unmap().
If given valid arguments, bus_dmamem_unmap() always succeeds.
Behavior is undefined if invalid arguments are passed to bus_dmamem_mmap().
Returns -1 to indicate failure. Otherwise, returns an opaque value to be interpreted by the device pager.
Jason Thorpe, A Machine-Independent DMA Framework for NetBSD, Proceedings of the FREENIX Track: 1998 USENIX Annual Technical Conference, USENIX Association, 1-12, June 15-19, 1998, http://www.usenix.org/publications/library/proceedings/usenix98/freenix/thorpe_dma.pdf.
July 8, 2011 | NetBSD 5.99 |